跳到主要内容

71 篇博文 含有标签「Beancount」

查看所有标签

解构 Beancount 账本:企业会计案例研究

· 阅读需 3 分钟
Mike Thrift
Mike Thrift
Marketing Manager

在今天的博客文章中,我们将深入剖析一个专为企业设计的 Beancount 账本,帮助你理解这种纯文本复式记账系统的复杂细节。

解构 Beancount 账本:企业会计案例研究

我们先从代码开始:

2023-05-22-business-template

1970-01-01 open Assets:Bank:Mercury
1970-01-01 open Assets:Crypto

1970-01-01 open Equity:Bank:Chase

1970-01-01 open Income:Stripe
1970-01-01 open Income:Crypto:ETH

1970-01-01 open Expenses:COGS
1970-01-01 open Expenses:COGS:Contabo
1970-01-01 open Expenses:COGS:AmazonWebServices

1970-01-01 open Expenses:BusinessExpenses
1970-01-01 open Expenses:BusinessExpenses:ChatGPT

2023-05-14 * "CONTABO.COM" "Mercury Checking ••1234"
Expenses:COGS:Contabo 17.49 USD
Assets:Bank:Mercury -17.49 USD

2023-05-11 * "Amazon Web Services" "Mercury Checking ••1234"
Expenses:COGS:AmazonWebServices 14490.33 USD
Assets:Bank:Mercury -14490.33 USD

2023-03-01 * "STRIPE" "Mercury Checking ••1234"
Income:Stripe -21230.75 USD
Assets:Bank:Mercury 21230.75 USD

2023-05-18 * "customer_182734" "0x5190E84918FD67706A9DFDb337d5744dF4EE5f3f"
Assets:Crypto -19 ETH {1,856.20 USD}
Income:Crypto:ETH 19 ETH @@ 35267.8 USD

理解代码

  1. 开立账户:代码首先在 1970-01-01 开立了一系列账户。其中包括资产账户(Assets:Bank:MercuryAssets:Crypto)、权益账户(Equity:Bank:Chase)、收入账户(Income:StripeIncome:Crypto:ETH)以及费用账户(Expenses:COGSExpenses:COGS:AmazonWebServicesExpenses:BusinessExpensesExpenses:BusinessExpenses:ChatGPT)。

  2. 交易记录:接着,代码记录了 2023-03-01 至 2023-05-18 期间的一系列交易。

    • 2023-05-14 的交易表示从 Mercury Checking ••1234CONTABO.COM 支付了 17.49 美元。这笔交易被记录为一项费用(Expenses:COGS:Contabo),并相应地从 Assets:Bank:Mercury 账户中扣除。

    • 同样,2023-05-11 的交易表示从同一银行账户向 Amazon Web Services 支付了 14490.33 美元。这笔交易记录在 Expenses:COGS:AmazonWebServices 下。

    • 2023-03-01 的交易显示来自 STRIPE 的收入存入 Mercury Checking ••1234,总计 21230.75 美元。这笔交易被记录为收入(Income:Stripe),并增加到银行账户(Assets:Bank:Mercury)中。

    • 2023-05-18 的最后一笔交易代表一笔涉及客户 19 ETH 的加密货币交易。这笔交易记录在 Assets:CryptoIncome:Crypto:ETH 下。{1,856.20 USD} 显示了交易时 ETH 的价格,而 @@ 35267.8 USD 则指明了这笔 19 ETH 交易的总价值。

在所有交易中,都遵循了复式记账原则,确保 资产 = 负债 + 权益 的等式始终成立。

总结

这个 Beancount 账本提供了一个直接而强大的财务交易追踪系统。正如最后一笔交易所示,Beancount 足够灵活,可以核算加密货币等非传统资产,这证明了它在我们日益数字化的金融环境中的实用性。

我们希望这次剖析能帮助你更好地理解 Beancount 的结构和功能,无论你是经验丰富的会计师还是尝试管理个人财务的初学者。敬请关注我们的下一篇博客文章,届时我们将深入探讨 Beancount 的高级操作。

重新推出新客户免费计划

· 阅读需 2 分钟
Mike Thrift
Mike Thrift
Marketing Manager

我们很高兴地宣布,自2023年5月1日起,我们将重新推出面向新客户的免费计划。这一决定是在我们对平台进行重大改进并优化资源之后做出的,旨在更好地服务所有客户,无论是免费用户还是付费用户。

推出面向新客户的全新免费计划

免费计划一直是我们愿景的重要组成部分,即为所有人提供可访问且用户友好的服务。我们相信,过去几个月所做的改进将使我们能够为用户提供更好的体验,同时保持对专业版计划客户的服务质量。

2023-04-28-start-serving-free-users

2023年5月1日之后注册的新客户将可以使用免费计划。

**你的支持和忠诚是本次免费计划得以重新推出的重要财务保障。**正是通过你的贡献,我们才得以投资于我们的基础设施和支持系统,确保我们能够继续提供你所期望的高质量服务,同时为新用户扩展我们平台的访问权限。你对我们愿景的承诺帮助我们成长和发展,我们衷心感谢你持续的合作。我们正在共同建设一个蓬勃发展的社区,并赋能各行各业的用户实现他们的目标。

如果你有任何疑问或疑虑,请随时与我们联系。我们随时乐意听取你的反馈并解决你可能遇到的任何问题。感谢你一直以来的支持,我们期待为你提供最优质的服务。

Beancount 速查表

· 阅读需 2 分钟
Mike Thrift
Mike Thrift
Marketing Manager

账户名称示例

Assets:US:BofA:Checking

cheatsheet-en

账户类型

Assets          +
Liabilities -
Income -
Expenses +
Equity -

商品/货币

CNY, EUR, CAD, AUD
GOOG, AAPL, RBF1005
HOME_MAYST, AIRMILES
HOURS

指令

通用语法

YYYY-MM-DD <Directive> <Parameters...>

开立与关闭账户

2001-05-29 open Expenses:Restaurant
2001-05-29 open Assets:Checking USD,EUR ; 货币限制

2015-04-23 close Assets:Checking

声明商品/货币 (可选)

1998-07-22 commodity AAPL
name: "苹果电脑公司"

价格

2015-04-30 price AAPL   125.15 CNY
2015-05-30 price AAPL 130.28 CNY

备注

2013-03-20 note Assets:Checking "致电询问回扣事宜"

文档

2013-03-20 document Assets:Checking "path/to/statement.pdf"

交易

2015-05-30 * "关于此交易的描述"
Liabilities:CreditCard -101.23 CNY
Expenses:Restaurant 101.23 CNY

2015-05-30 ! "有线电视公司" "电话账单" #tag ˆlink
id: "TW378743437" ; 元数据
Expenses:Home:Phone 87.45 CNY
Assets:Checking ; 你可以省略其中一个金额

分录

  ...    123.45 USD                             简单
... 10 GOOG {502.12 USD} 带单位成本
... 10 GOOG {{5021.20 USD}} 带总成本
... 10 GOOG {502.12 # 9.95 USD} 带两种成本
... 1000.00 USD @ 1.10 CAD 带单位价格
... 10 GOOG {502.12 USD} @ 1.10 CAD 带成本与价格
... 10 GOOG {502.12 USD, 2014-05-12} 带日期
! ... 123.45 USD ... 带标记

余额断言与填充

; 仅断言指定货币的金额:
2015-06-01 balance Liabilities:CreditCard -634.30 CNY

; 自动插入交易以满足以下断言:
2015-06-01pad Assets:Checking Equity:Opening-Balances

事件

2015-06-01 event "location" "美国纽约"
2015-06-30 event "address" "梅街123号"

选项

option "title" "我的个人账本"

其他

pushtag #trip-to-peru
...
poptag #trip-to-peru
; 注释以分号开头

Beancount 纯文本记账的魔力

· 阅读需 6 分钟
Mike Thrift
Mike Thrift
Marketing Manager

探索 Beancount 纯文本记账的魔力

Beancount.io 横幅

引言

2023-04-18-Beancount 介绍

欢迎来到一个记账不再是艰巨任务的世界。今天,我们向你介绍 Beancount,一个强大、灵活且直观的纯文本记账工具。Beancount 通过提供透明、直接的资金管理方法,让你能够掌控自己的财务。

在这份全面的指南中,我们将深入探讨 Beancount 的基础知识,解释其核心概念,并引导你了解其简单而强大的功能。阅读完这篇博客,你将对 Beancount 有扎实的理解,并准备好开始使用它来整理和分析你的财务生活。

什么是 Beancount?

Beancount 是由 Martin Blais 创建的一个开源纯文本记账系统。受 John Wiegley 的 Ledger 系统启发,Beancount 旨在提供一种强大可靠的方法,使用纯文本文件管理个人和小型企业的财务。通过 Beancount,你可以轻松追踪你的收入、支出、投资等等。

为什么选择 Beancount?

纯文本记账相比传统的基于电子表格或软件的记账系统具有多项优势:

  • 透明度:Beancount 文件是人类可读的,这使得理解和审计你的财务数据变得容易。
  • 灵活性:Beancount 可以轻松定制以满足你的特定需求,你可以使用你喜欢的文本编辑器和版本控制系统来管理你的财务数据。
  • 便携性:你的财务数据可以在任何设备上访问,并且易于在系统之间传输或与他人共享。
  • 面向未来:纯文本文件具有通用兼容性,确保你的财务数据即使随着技术发展也能保持可访问性。

Beancount 的核心概念

要有效使用 Beancount,理解其核心概念至关重要:

  • 交易:财务事件,例如收入、支出或账户之间的转账,都记录为交易。
  • 账户:交易涉及一个或多个账户,例如资产、负债、收入或支出。
  • 复式记账:Beancount 强制执行复式记账,确保每笔交易都有平衡的借方和贷方。
  • 指令:Beancount 使用一组指令来定义交易、账户开立和其他财务事件。

Beancount 入门

要开始使用 Beancount,请遵循以下简单步骤:

  • 安装 Beancount:根据你操作系统的安装说明,在你的系统上安装 Beancount。
  • 创建你的 Beancount 文件:创建一个新的纯文本文件,扩展名为 .beancount(例如,my_finances.beancount)。
  • 定义你的账户:使用 "open" 指令定义你将在交易中使用的账户。
  • 记录交易:使用 "txn" 指令记录你的财务交易。

或者直接在 https://beancount.io 注册。以下是一些纯文本记账示例 -

示例 1:基本交易

2023-04-01 open Assets:Checking
2023-04-01 open Expenses:Groceries

2023-04-10 txn "Grocery Store" "Buying groceries"
Assets:Checking -50.00 USD
Expenses:Groceries 50.00 USD

在此示例中,我们开立了两个账户:Assets:Checking(资产:活期账户)和 Expenses:Groceries(支出:食品杂货)。2023 年 4 月 10 日,我们记录了一笔价值 50 美元的购买食品杂货的交易。该交易使 Assets:Checking 的余额减少 50 美元(借方),并使 Expenses:Groceries 的余额增加 50 美元(贷方)。

示例 2:收入和支出交易

2023-04-01 open Assets:Checking
2023-04-01 open Income:Salary
2023-04-01 open Expenses:Rent

2023-04-05 txn "Employer" "Salary payment"
Assets:Checking 2000.00 USD
Income:Salary -2000.00 USD

2023-04-06 txn "Landlord" "Monthly rent payment"
Assets:Checking -1000.00 USD
Expenses:Rent 1000.00 USD

在此示例中,我们开立了三个账户:Assets:Checking(资产:活期账户)、Income:Salary(收入:工资)和 Expenses:Rent(支出:租金)。2023 年 4 月 5 日,我们记录了一笔 2000 美元的工资支付交易。该交易使 Assets:Checking 的余额增加 2000 美元(贷方),并使 Income:Salary 的余额减少 2000 美元(借方)。2023 年 4 月 6 日,我们记录了一笔 1000 美元的月租支付交易。该交易使 Assets:Checking 的余额减少 1000 美元(借方),并使 Expenses:Rent 的余额增加 1000 美元(贷方)。

示例 3:账户间转账

2023-04-01 open Assets:Checking
2023-04-01 open Assets:Savings

2023-04-15 txn "Bank" "Transfer from Checking to Savings"
Assets:Checking -500.00 USD
Assets:Savings 500.00 USD

在此示例中,我们开立了两个账户:Assets:Checking(资产:活期账户)和 Assets:Savings(资产:储蓄账户)。2023 年 4 月 15 日,我们记录了一笔从活期账户向储蓄账户转账 500 美元的交易。该交易使 Assets:Checking 的余额减少 500 美元(借方),并使 Assets:Savings 的余额增加 500 美元(贷方)。

这些示例说明了 Beancount 复式记账系统的基本概念。通过正确记录交易,用户可以维护其财务活动的准确记录,并生成报告以深入了解其财务状况。

生成报告和分析数据

Beancount 附带了一套强大的工具,用于生成财务报告,包括资产负债表、利润表等。你还可以使用 Fava(一个基于 Web 的 Beancount 用户界面)来可视化和交互你的财务数据。https://beancount.io 是基于 MIT 许可证的 Fava 构建的。

结论

拥抱 Beancount 纯文本记账的强大和简洁。通过理解其核心概念并遵循本指南中概述的步骤,你将能够轻松精确地管理你的个人或小型企业财务。随着你对 Beancount 越来越熟悉,你可以探索高级功能和自定义设置,以根据你的独特需求调整系统。

无论你是想追踪支出、规划未来,还是深入了解你的财务习惯,Beancount 都提供了实现目标所需的灵活性和透明度。凭借其用户友好的方法,Beancount 有潜力彻底改变你管理财务的方式,并赋能你掌控自己的财务未来。

现在你已经对 Beancount 有了坚实的基础,是时候开始你的纯文本记账之旅了。告别繁琐的电子表格和复杂的软件,欢迎来到 Beancount 的世界。祝你记账愉快!

通过自定义链接和查询提升你的 Beancount 体验

· 阅读需 4 分钟
Mike Thrift
Mike Thrift
Marketing Manager

Beancount,这个深受开发者和财务爱好者喜爱的复式记账系统,以其简洁性而强大。但是,对于那些希望在 Beancount 的网页界面 Fava 中获得更多控制和更快导航的用户来说,自定义侧边栏链接和 SQL 查询可以将你的工作流提升到新的水平。

在本指南中,我们将向你展示如何:

  • 在 Fava 的侧边栏添加快速访问链接
  • 使用 SQL 查询进行高级筛选和分析
  • 为月度审查或异常检测自定义你的工作流

为什么要自定义 Fava?

Fava 已经是查看你的 Beancount 账本的精美界面,但随着你的日记账不断增长,对更好快捷方式和更智能查询的需求也随之增加。

这解决了以下痛点:

  • 重复导航时间范围
  • 跨嵌套账户筛选交易
  • 更快地发现负余额或异常

✨ 自定义侧边栏链接

让我们从使用简单的侧边栏快捷方式改进你的日常工作流开始。这些链接会出现在 Fava 的左侧边栏,可以直接带你进入筛选视图,例如本月交易或上月收入。

将以下行添加到你的 Beancount 文件中:

2021-01-01 custom "fava-sidebar-link" "Current Month" "/jump?time=month"
2021-01-01 custom "fava-sidebar-link" "Last Month" "/jump?time=month-1"
2021-01-01 custom "fava-sidebar-link" "Clear All" "/jump?account=&time=&filter="

它们的作用:

  • 本月: 打开筛选到当前月份的交易视图。
  • 上月: 立即跳转到上个月——非常适合月末审查。
  • 清除所有: 重置筛选器,再次显示所有条目。

这些快捷方式消除了手动输入时间,让你的 Fava 体验更加流畅和个性化。

🔍 自定义 SQL 查询

为了获得更深入的洞察,Fava 的 SQL 界面功能强大得令人难以置信。这是一个查询,用于查找符合特定模式的账户中的所有负余额——非常适合标记异常或有问题的交易。

SELECT account, units(sum(position)), sum(position)
WHERE number(units(position)) < 0
AND account ~ '.*:BCM:.*'
AND date >= DATE(2021,12,9)
AND date < DATE(2022,1,9)

解析:

  • account ~ '.*:BCM:.*':筛选名称中包含 :BCM: 的账户。
  • number(units(position)) < 0:标记负余额(例如,预算超支)。
  • 日期筛选器将结果范围缩小到特定的 1 个月窗口。

用例:

  • 发现重复支出或错误过账等错误
  • 审计特定供应商或类别
  • 快速提取可操作的预算洞察

🛠 专业提示:结合链接 + 查询

虽然 Fava 不允许直接链接到自定义查询,但你可以通过以下方式养成每月审查的习惯:

  • 使用“本月”链接开始你的审查
  • 在另一个窗格中打开你保存的查询选项卡
  • 同时审查两者——先筛选,然后深入挖掘

这种组合有助于你在异常恶化之前发现它们确保你的账本保持整洁

总结

Beancount 的设计理念是极简,但像这些小小的增强功能却能带来巨大的效率提升。无论你是在审查预算、调试异常余额,还是仅仅为了节省点击次数,自定义链接和 SQL 查询都能为你提供更大的能力和更少的阻碍。

额外提示: 如果你正在使用 Fava 的自定义报告,你甚至可以构建完全符合你个人财务习惯的仪表板。

准备好掌控一切了吗?

从小处着手:添加“本月”链接。然后构建你自己的查询。未来的你会感谢你的。

想要更多此类技巧?订阅我们的新闻通讯或在 Beancount.io 探索更多 Beancount 秘籍。

Beancount 中未来交易的预测

· 阅读需 1 分钟
Mike Thrift
Mike Thrift
Marketing Manager

Beancount 有一个插件可以预测未来的周期性交易。如何在 beancount.io 中应用它?将以下内容放入你的账本文件中。

; import the plugin
plugin "fava.plugins.forecast"

; add a monthly HOA fee
2022-05-30 # "HOA fee [MONTHLY]"
Expenses:Hoa 1024.00 USD
Assets:Checking -1024.00 USD

预测插件截图

2022-05-30-预测插件

然后,你将在净利润图表中看到预测结果。

预测插件

上面的标签 [MONTHLY] 意味着它将永久循环。如果你有更多条件需要应用,请尝试 [MONTHLY UNTIL 2022-06-01][MONTHLY REPEAT 5 TIMES][YEARLY REPEAT 5 TIMES][WEEKLY SKIP 1 TIME REPEAT 5 TIMES]

使用 Beancount 制作和追踪发票

· 阅读需 6 分钟
Mike Thrift
Mike Thrift
Marketing Manager

一个纯文本模板、一个可重复的工作流程和一个简单的查询,即可解答“还有谁欠我钱?”


2022-02-12-crafting-tracking-invoices-with-beancount

开票工作有时感觉像是一件苦差事,卡在你已完成的工作和你正在等待的付款之间。 但是,良好的开票流程是健康现金流的支柱。 它具有双重作用:清晰地告知你的客户他们欠款多少以及何时付款,并为你的会计系统提供其所需的可靠事实。

虽然专用的 SaaS 应用程序可以发送流畅的自动化 PDF 文件,但它们通常需要按月付费,并将你的数据锁定在专有孤岛中。 使用 Beancount 的轻量级纯文本方法提供了一个强大的替代方案。 你可以将每张发票转换为一组清晰的会计分录,从而获得版本控制、强大的元数据和即时查询的所有好处,而无需订阅。


最小可行发票(你永远不应该跳过的字段)

在接触你的账本之前,你需要一张专业的发票。 格式可以很简单,但内容必须精确。 这些借鉴久经考验的小企业实践的字段是不可协商的。

  • 卖方详细信息: 你的公司名称和实际地址。
  • 客户详细信息: 你的客户的名称和(理想情况下)他们的地址。
  • 发票编号: 一个唯一的、连续的 ID,永不重复使用。 INV-045 紧随 INV-044 之后。
  • 开票日期和到期日期: 清楚地说明发票的开具日期和预期付款日期。
  • 项目明细: 对服务或产品的清晰描述,以及数量、单价和项目总计。
  • 小计、税金和总计: 显示计算过程,以便客户可以轻松理解。
  • 可选注释: 用于感谢、汇款指示或客户提供的采购订单号。

为了帮助你入门,我们创建了一组可立即编辑的模板,其中包含所有这些字段。 电子表格版本甚至会为你预先计算总计。

Note: Invoice templates are coming soon! In the meantime, you can create your own using the fields listed above in Google Docs, Word, Sheets, Excel, or any other document format.


在你的账本中记录发票

将发票 PDF 发送给客户后,你必须将其记录在 Beancount 中。 这是一个至关重要的步骤,它在收入产生时确认收入,而不仅仅是在收到付款时。 该过程涉及两个不同的交易。

1. 开具发票时:

你创建一个交易,将总金额从你的 Income 账户转移到 Assets:AccountsReceivable。 这会在你的账簿中创建一个数字借据。

; 2025‑07‑21 发票 #045  为 Acme Corp. 进行的网页设计冲刺
2025-07-21 * "Acme Corp" "INV-045 网页设计冲刺"
Assets:AccountsReceivable 3500.00 USD ; due:2025-08-04
Income:Design:Web
invoice_id: "INV-045"
contact_email: "ap@acme.example"
link: "docs/invoices/2025-07-21_Acme_INV-045.pdf"

在这里,你借记 AccountsReceivable 并贷记你的 Income 账户。 请注意丰富的元数据:到期日期、唯一的 invoice_id,甚至直接指向你发送的 PDF 的 link:

2. 客户付款时:

当现金存入你的银行账户时,你记录第二个交易以“结清”借据。 这会将余额从 AccountsReceivable 转移到你的支票账户。

2025-08-01 * "Acme Corp" "INV-045 付款"
Assets:Bank:Checking 3500.00 USD
Assets:AccountsReceivable
invoice_id: "INV-045"

Assets:AccountsReceivableINV-045 的余额现在为零,你的账簿完全平衡。

附加 PDF: link: 元数据键与 Fava(Beancount 的 Web 界面)一起使用时尤其强大。 Fava 将直接在交易视图中呈现可点击的链接,因此只需点击一下即可访问源文档。 此工作流程早在 2016 年就在一项功能请求中设想 (GitHub)。


一个查询即可列出所有未结发票

那么,还有谁欠你钱? 使用此系统,你无需在电子邮件或电子表格中查找。 你只需要一个简单的查询。

将以下内容保存为名为 open-invoices.sql 的文件:

SELECT
meta('invoice_id') AS id,
payee,
narration,
date,
number(balance) AS outstanding
WHERE
account = "Assets:AccountsReceivable"
AND balance != 0
ORDER BY
date;

现在,从你的命令行运行它:

bean-query books.beancount open-invoices.sql

几秒钟内,你将获得一份清晰的、最新的所有未结发票的账龄报告,其中显示发票 ID、客户、开票日期和欠款金额。 无需额外的软件。


自动化繁琐的工作

纯文本的优点在于可编写脚本。 你可以自动化此工作流程中繁琐的部分。

  • 模板 + Pandoc = PDF: 以 Markdown 格式维护你的发票模板。 一个小型 Python 脚本可以填充变量(客户名称、项目明细、发票编号),命令行工具 Pandoc 可以立即将其转换为专业的 PDF。
  • Git 预提交钩子: 如果你将账本存储在 Git 中,一个简单的预提交钩子可以在你保存工作之前运行检查。 它可以验证每个新的 invoice_id 是否唯一,交易过账是否平衡为零,以及 link: 元数据中引用的文件是否实际存在。
  • Cron 作业: 设置计划任务(cron 作业)以每晚运行你的 open-invoices.sql 查询并通过电子邮件向你发送摘要。 你将每天开始工作时确切地知道谁需要友好的提醒。

现实的警告

Beancount 是一个会计工具,而不是开票_服务_。 它不会自动向你的客户发送付款提醒或处理他们的信用卡付款。 工作流程是:你使用你选择的方法(例如上面的模板)创建并发送发票,然后在你的账本中记录会计分录。

对于大多数自由职业者和小商店来说,这个手动步骤对于一个完全拥有和控制的、防弹的、可审计的免费会计系统来说是一个很小的代价 (beancount.io)。


后续步骤

准备好控制你的开票了吗? 以下是开始的方法。

  1. 下载模板并使用它创建你的下一个真实发票,确保使用连续的发票编号。
  2. 将你发送的 PDF存储在专用文件夹中,例如 docs/invoices/,并在你的 Beancount 交易中使用 link: 元数据键来引用它们。
  3. 保存 open-invoices.sql 查询并将其作为你每周财务审查的一部分运行。

纯文本会计并不意味着放弃完善或控制——它只是意味着数据库是可 grep 的。 使用简单的模板和上面的代码片段,你将更快地获得付款_并且_保持你的账簿整洁。

Beancount 中的调整分录:月末财务核对

· 阅读需 5 分钟
Mike Thrift
Mike Thrift
Marketing Manager

会计工作并不在最后一笔销售款到账时就结束了。为了真实了解你的业务健康状况,你需要进行月末财务核对。在每个期末,你都需要进行调整分录——对日记账进行调整,将收入和支出正确地归入相应的期间,并确保资产负债表的准确性。

在纯文本 Beancount 账本中,这些关键分录是透明的、版本可控的,并且易于审计,将繁琐的任务转化为清晰且可重复的流程。

2022-01-25-adjusting-entries-in-beancount-your-month-end-tune-up


为什么调整分录很重要

进行这些调整是健全会计的基础。它们确保你的财务报表准确可靠。

  • 权责发生制准确性: 调整分录是权责发生制会计的引擎。它们将收入和成本移至实际赚取或发生的期间,而不管现金何时易手。这满足了构成现代会计基础的核心收入确认配比原则AccountingCoach.com)。

  • 可靠的关键绩效指标: 关键绩效指标的质量取决于其背后的数据。只有在正确过账递延、应计和估计后,毛利率、净收入和现金流量预测等指标才能反映真实情况(Corporate Finance Institute)。

  • 清晰的审计线索: 明确的月末调整可以创建清晰的财务推理记录。这有助于审计员(以及你未来的自己)轻松追踪变化的内容和原因,从而建立对你数字的信心(Accountingverse)。


六个常见类别(附 Beancount 代码片段)

以下是六种最常见的调整分录类型,以及如何在 Beancount 账本中记录它们的示例。请注意使用 adj:"accrual" 等元数据,以便以后轻松查找和分析这些分录。

1. 应计收入

这是指你已赚取但尚未开具账单或收到付款的收入。

2025-07-31 * "咨询——7 月工时"
Assets:AccountsReceivable 12000.00 USD
Income:Consulting
; adj:"accrual" period:"Jul-25"

2. 应计费用

你已发生但尚未支付的费用,例如将于下个月收到的水电费账单。

2025-07-31 * "律师——7 月预付金"
Expenses:Legal 2500.00 USD
Liabilities:AccruedPayables
; adj:"accrual"

3. 递延(预收)收入

这适用于客户提前付款的情况。你将随着时间的推移确认已赚取的那部分收入。

2025-07-31 * "年度 SaaS 预付款(确认 1/12)"
Liabilities:UnearnedRevenue 833.33 USD
Income:SaaS
; adj:"deferral"

4. 预付(递延)费用

当你预先支付费用时(例如年度保险费),你每月将其一部分计入费用。

2025-07-31 * "保险——预付费用中的 1 个月费用"
Expenses:Insurance 400.00 USD
Assets:PrepaidInsurance
; adj:"deferral"

5. 折旧和摊销

此分录将长期资产(例如计算机或车辆)的成本在其使用寿命内进行分配。

2025-07-31 * "Mac Studio 折旧"
Expenses:Depreciation 1250.00 USD
Assets:Computers:AccumDepr
; asset_id:"MAC-03" adj:"estimate"

6. 坏账准备

你预计无法收回的应收账款的估计值,记为坏账费用。

2025-07-31 * "坏账准备金(应收账款的 2%)"
Expenses:BadDebt 700.00 USD
Assets:AllowanceForBadDebt
; basis:"A/R" rate:0.02 adj:"estimate"

可重复的工作流程

为了保持月末结算的高效性和无差错性,请采用一致的工作流程。

  • 使用单独的文件。 将一个期间的所有调整保存在一个位置,例如 adjustments-2025-07.bean。在你的主账本文件中,使用 include 指令将其最后导入。这可确保在生成最终报告之前应用调整。

  • 标准化你的元数据。 始终使用一致的元数据键和值,例如 adj:"accrual|deferral|estimate"period:"Jul-25"。这使得查询和审查特定类型的调整变得轻而易举。

  • 运行预检。 在将更改提交到 Git 之前,对你的调整文件运行 bean-check 以捕获任何拼写错误或不平衡的过账。

  • 执行单行健全性检查。 此查询确认你该期间的所有调整是否平衡,让你确信没有引入错误。

    bean-query main.bean "SELECT account, SUM(number) WHERE meta('adj') AND meta('period') = 'Jul-25' GROUP BY account"

快速故障排除技巧 🤔

  • 你的 Liabilities:UnearnedRevenue 余额是否不断攀升? 检查你的合同里程碑。与你交付的工作相比,你确认收入的速度可能太慢。

  • 你的 Assets:PrepaidInsurance 余额是否为负? 你可能以比资产计划允许的速度更快的速度将其计入费用。仔细检查你的摊销计划。

  • 你的平均收款期 (DSO) 在应计后是否变得更糟? 你的应计收入可能掩盖了潜在的收款问题。将此 KPI 与应收账款账龄报告配对,以便在成为现金流问题之前发现逾期付款的客户。


结束语

调整分录可能会让人觉得乏味,但是当你比较“调整前”和“调整后”的损益表时,它们的价值就变得清晰可见——差异通常很大。使用 Beancount,这些调整变成了小的、可搜索的补丁,你可以像代码一样对其进行自动化和审查。

养成月末调整的习惯,你的数字将与你的工程一样准确。

祝你平衡愉快!

Beancount.io 革新个人财务管理

· 阅读需 4 分钟
Mike Thrift
Mike Thrift
Marketing Manager

传统的 Beancount 用户通常使用命令行工具或在私有网络中自建服务器,他们必须通过电脑或移动设备上的通用文本编辑器进行操作。Beancount.io 通过提供开源的 Android 和 iOS 移动应用以及安全的云服务来减少这些麻烦,让你的账本现在只需轻点几下即可通过指纹访问。

Beancount 是一种计算机语言,可以在文本文件中实现复式记账。一旦你在文件中定义了财务交易,它就会生成各种报告。这种语言的设计者 Martin Blais 认为,命令行记账具有许多优点——它快速、便携、开放且可定制。

我们强烈认同这一观点,并分享 Beancount 语言所带来的赋能感。我们希望做得更多——将这项技术介绍给更多人。这意味着我们必须提高可用性,使其更容易被更广泛的用户群体所使用。

2022-01-08-instant-access-to-your-beancount-cloud-ledger-anytime-anywhere

并非每个人都是命令行爱好者,这就是我们构建 Beancount.io 的原因——一个面向所有人的个人财务管理器。它的工作方式如下:

对于繁重的工作,Beancount 用户仍然可以使用他们的电脑,通过浏览器访问 https://beancount.io 或与 Dropbox 同步来编辑或查看账本。这既保留了命令行工具的灵活性,又没有失去云端解决方案的跨设备访问能力。

对于日常轻量级操作,例如即时添加条目,Beancount 用户可以使用移动应用连接到安全云。

负责此产品的后端工程师 Mike Thrift 说:

我过去每天都会设置提醒,让自己打开笔记本电脑并将记录输入到我的 Beancount 文件中。现在,有了 Beancount.io,我可以在需要时更轻松地修改我的账本,即使我在户外商店购物时也能做到。

Facebook 软件工程师 Zhi Li 告诉我们:

我已经将我所有的 Beancount 文件迁移到 Beancount.io,现在它非常适合我的日常使用。我购买了自动数据备份等专业版功能,但我认为你们还可以做更多事情来改进服务。

你现在可以在 https://beancount.io/sign-up/ 注册,或下载 iOSAndroid 应用。我们简化了注册流程,尽可能少地收集你的信息来启动服务。然后你将获得一个预设的空账本,你可以立即添加条目。

常见问题

Beancount.io 会将我的账本数据出售给任何第三方吗?

  • 不会。我们致力于确保你的数据安全和隐私,我们绝不会出售你的账本数据。

我的数据安全吗?

  • 是的。我们使用 AES256 保护你的电子邮件和账本,使用 BCrypt 保护你的密码,并使用 SSL 保护你的网络请求。

我的账本数据是端到端加密的吗?

  • 不是。由于技术限制,在生产服务器中索引账本文件时,我们仍然必须将你的数据解密到内存中。因此,我们限制我们任何团队成员的直接访问。不幸的是,由于成本高昂,我们无法在 Intel 的 SGX 或任何安全保险库中实现这一点。

这是一项未来几年我可以信赖的可靠服务吗?

  • 是的。我们最初于 2019 年 7 月 4 日推出了 Beancount.io,并且我们已经安全可靠地运营该服务两年多了。因此,我们没有理由不继续在未来提供服务。

我可以请求新功能并赞助项目吗?

QuickBooks 到 Beancount 迁移指南

· 阅读需 32 分钟
Mike Thrift
Mike Thrift
Marketing Manager

阶段一:从 QuickBooks 导出数据

迁移五年的数据,第一步是把所有 QuickBooks 记录以可用的格式导出来。QuickBooks 桌面版和 QuickBooks 在线版有不同的导出选项:

2021-12-01-from-quickbooks-to-plain-text-a-migration-playbook

1.1 QuickBooks 桌面版 – 导出选项

IIF (Intuit Interchange Format): QuickBooks 桌面版可以将列表(如会计科目表、客户、供应商)导出为 .IIF 文本文件。在 QuickBooks 桌面版中,进入 文件 (File) → 实用程序 (Utilities) → 导出 (Export) → 列表到 IIF 文件 (Lists to IIF),然后选择你需要的列表(例如,会计科目表、客户、供应商)。这将生成一个包含账户名称、类型和列表数据的文本文件。IIF 是一种专有但易于解析的纯文本格式。用它来获取你的会计科目表和联系人列表,以便在 Beancount 中参考。

总分类账/日记账(通过 CSV): 对于交易数据,QuickBooks 桌面版没有一键式完整导出功能,但你可以使用报表。推荐的方法是导出所需日期范围内的总日记账(所有交易)。在 QuickBooks 桌面版中,打开 报表 (Reports) → 会计与税务 (Accountant & Taxes) → 日记账 (Journal),将日期设置为从最早的交易到今天,然后点击 导出 (Export) → Excel。在移除报表页眉/页脚和空列后,将结果另存为 CSV。确保数值数据是干净的:包含小数(例如 3.00 而不是 3),没有多余的引号,CSV 中没有货币符号或双重负号。CSV 文件应包含 日期 (Date)、交易号 (Trans #)、名称 (Name)、账户 (Account)、备注 (Memo)、借方 (Debit)、贷方 (Credit)、余额 (Balance) 等列(或根据报表格式只有单个金额列)。

提示: QuickBooks 桌面版 2015+ 也可以通过 查找 (Find) 对话框导出交易。使用 编辑 (Edit) → 查找 (Find) → 高级 (Advanced),设置五年的日期范围,然后将结果导出为 CSV。警告: 某些版本将导出限制在 32,768 行。如果你的数据量非常大,请逐年(或分更小的块)导出以避免数据被截断,然后再将它们合并。确保日期范围不重叠以防止重复。

其他格式 (QBO/QFX/QIF): QuickBooks 桌面版可以通过 .QBO (Web Connect) 或 .QFX/.OFX 文件导入银行交易,但对于 QuickBooks 导出,这些不是常规选项。如果你的目标只是提取银行交易,你可能已经从银行那里获得了 QBO/OFX 文件。然而,对于完整的分类账导出,请坚持使用 IIF 和 CSV。QuickBooks 桌面版不能直接导出到 QIF (Quicken Interchange Format) 格式,除非使用第三方工具。如果你确实找到了获取 QIF 的方法,请注意一些账本工具(旧版的 Ledger 2.x)可以读取 QIF,但在我们的流程中,最好还是使用 CSV。

1.2 QuickBooks 在线版 – 导出选项

内置 Excel/CSV 导出: QuickBooks 在线版 (QBO) 提供了一个导出数据工具。进入 设置 ⚙ → 工具 (Tools) → 导出数据 (Export Data)。在导出对话框中,使用报表 (Reports) 标签选择数据(例如总分类账或交易列表),并使用列表 (Lists) 标签选择列表(会计科目表等),选择所有日期 (All dates),然后导出到 Excel。QuickBooks 在线版将下载一个 ZIP 文件,其中包含所选报表和列表的多个 Excel 文件(例如,利润表、资产负债表、总分类账、客户、供应商、会计科目表等)。然后你可以将这些 Excel 文件转换为 CSV 进行处理。

交易明细报表: 如果 QBO 的默认导出不包含单个总分类账文件,你可以手动运行一个详细报表:

  1. 导航到报表 (Reports) 并找到按账户交易明细 (Transaction Detail by Account)(在某些 QBO 版本中是总分类账 (General Ledger))。
  2. 报表期间 (Report period) 设置为完整的五年范围。
  3. 在报表选项下,将分组依据 (Group by) 设置为无 (None)(以便列出单个交易而不是小计)。
  4. 自定义列,至少包括:日期 (Date)、交易类型 (Transaction Type)、编号 (Number)、名称 (Name, Payee/Customer)、备注/描述 (Memo/Description)、账户 (Account)、借方 (Debit)贷方 (Credit)(或单个金额列),以及余额 (Balance)。如果使用了类别 (class) 或地点 (location),也请包含它们。
  5. 运行报表,然后导出到 Excel (Export to Excel)

这将生成一个包含所有交易的详细分类账。将其另存为 CSV。每一行代表一笔交易的一个分录 (split/posting)。之后你需要按交易对这些行进行分组以进行转换。

会计科目表及其他列表: QuickBooks 在线版可以通过 会计 (Accounting) → 会计科目表 (Chart of Accounts) → 批量操作 (Batch Actions) → 导出到 Excel (Export to Excel) 来导出会计科目表。这样做可以获取账户名称和类型。同样,如果你想保留名称作为元数据,也请导出客户、供应商等列表。

QuickBooks Online API (可选): 对于编程方法,Intuit 为 QBO 数据提供了 REST API。高级用户可以创建一个 QuickBooks Online 应用(需要开发者账户),并使用 API 以 JSON 格式获取数据。例如,你可以查询 Account 端点获取会计科目表,查询 JournalEntryGeneralLedger 报表端点获取交易。有像 python-quickbooks 这样的 Python SDK 可以封装 API。然而,使用 API 涉及 OAuth 身份验证,对于一次性迁移来说有些小题大做,除非你偏爱自动化。对于大多数情况,手动导出为 CSV/Excel 更简单且不易出错


阶段二:转换和清理数据

一旦你有了 CSV (和/或 IIF) 格式的 QuickBooks 数据,下一步就是将其转换为 Beancount 的纯文本账本格式。这包括解析导出的文件,将 QuickBooks 账户映射到 Beancount 的会计科目表,以及按 Beancount 语法格式化交易。

2.1 使用 Python 解析 QuickBooks 导出文件

使用 Python 将确保转换的准确性和可复现性。我们将概述两个关键任务的脚本:导入会计科目表转换交易

账户导入和映射: 在添加交易之前,在 Beancount 中设置好账户至关重要。QuickBooks 的账户有类型(银行、应收账款、费用等),我们将它们映射到 Beancount 的层级结构(资产、负债、收入、费用等)。例如,我们可以使用如下映射:

# QuickBooks 账户类型到 Beancount 根类别的映射
AccountTypeMap = {
'BANK': 'Assets',
'CCARD': 'Liabilities',
'AR': 'Assets', # 应收账款作为资产
'AP': 'Liabilities', # 应付账款作为负债
'FIXASSET': 'Assets',
'OASSET': 'Assets', # 其他资产
'OCASSET': 'Assets', # 其他流动资产
'LTLIAB': 'Liabilities', # 长期负债
'OCLIAB': 'Liabilities', # 其他流动负债
'EQUITY': 'Equity',
'INC': 'Income',
'EXP': 'Expenses',
'EXINC': 'Income', # 其他收入
'EXEXP': 'Expenses', # 其他费用
}

使用 QuickBooks 桌面版的 IIF 导出文件或 QBO 的账户列表 CSV,我们获取每个账户的名称和类型。然后:

  • 创建 Beancount 账户名称: QuickBooks 有时在账户名称中使用冒号 (:) 来表示子账户(例如 “Current Assets:Checking)。Beancount 使用相同的冒号表示法来表示层级。你通常可以直接重用该名称。如果 QuickBooks 账户名称不以类别开头,则在前面加上映射的类别。例如,一个类型为 BANK、名为 "Checking" 的 QuickBooks 账户在 Beancount 中将变为 Assets:Checking。一个 EXP (费用) 账户 "Meals" 变为 Expenses:Meals,依此类推。

  • 确保命名有效: 移除或替换任何可能混淆 Beancount 的字符。QuickBooks 允许名称中包含 &/ 等字符。明智的做法是剔除或替换特殊字符(例如,用 and 替换 &,移除斜杠或空格)。此外,确保转换后所有账户名称都是唯一的——QuickBooks 可能允许在不同父账户下有相同的子账户名,这没问题,但在 Beancount 中,完整的名称(包括父账户)必须是唯一的。如果需要,重命名或附加一个限定符以区分它们。

  • 输出账户开设指令: 在 Beancount 中,每个使用的账户都必须用 open 指令开设。你可以选择一个在第一笔交易之前的日期(例如,如果迁移 2019–2023 年的数据,对所有开设指令使用 2018-12-31 或更早的日期)。脚本将写出如下行: 2018-12-31 open Assets:Checking USD 2018-12-31 open Expenses:Meals USD 为每个账户都这样做(假设 USD 是主要货币)。为每个账户使用适当的货币(见下面的多币种说明)。

交易转换: 主要挑战是将 QuickBooks 导出的交易(CSV)转换为 Beancount 条目。每个 QuickBooks 交易(发票、账单、支票、日记账分录等)可能有多条分录(行),必须将它们收集到一个 Beancount 交易中。

我们将使用 Python 的 CSV 阅读器来迭代导出的行并累积成分录:

import csv
from collections import defaultdict

# 从 QuickBooks 日记账 CSV 中读取所有行
rows = []
with open('quickbooks_exported_journal.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for line in reader:
rows.append(line)

# 按交易分组(假设 'Trans #' 标识交易)
transactions = defaultdict(list)
for line in rows:
trans_id = line.get('Trans #') or line.get('Transaction ID') or line.get('Num')
transactions[trans_id].append(line)

现在 transactions 是一个字典,其中每个键是交易 ID/编号,值是该交易的分录列表。接下来,我们将每个组转换为 Beancount 格式:

def format_date(qb_date):
# QuickBooks 的日期可能是 "12/31/2019" 这样的格式
m, d, y = qb_date.split('/')
return f"{y}-{int(m):02d}-{int(d):02d}"

output_lines = []
for trans_id, splits in transactions.items():
# 如果需要,按行顺序对分录排序(通常它们是按顺序导出的)
splits = sorted(splits, key=lambda x: x.get('Line') or 0)
first = splits[0]
date = format_date(first['Date'])
payee = first.get('Name', "").strip()
memo = first.get('Memo', "").strip()
# 交易标题
output_lines.append(f"{date} * \"{payee}\" \"{memo}\"")
if first.get('Num'): # 如果有参考编号,则包含它
output_lines.append(f" number: \"{first['Num']}\"")
# 遍历每个分录/记账
for split in splits:
acct_name = split['Account'].strip()
# 将 QuickBooks 账户名映射到 Beancount 账户(使用之前的映射)
beancount_acct = account_map.get(acct_name, acct_name)
# 确定带符号的金额:
amount = split.get('Amount') or ""
debit = split.get('Debit') or ""
credit = split.get('Credit') or ""
if amount:
# 某些导出文件有一个 Amount 列(贷方为负数)
amt_str = amount
else:
# 如果有单独的 Debit/Credit 列
amt_str = debit if debit else f"-{credit}"
# 为安全起见,移除数字中的逗号
amt_str = amt_str.replace(",", "")
# 附加货币
currency = split.get('Currency') or "USD"
amt_str = f"{amt_str} {currency}"
# 分录的备注/描述
line_memo = split.get('Memo', "").strip()
comment = f" ; {line_memo}" if line_memo else ""
output_lines.append(f" {beancount_acct:<40} {amt_str}{comment}")
# 交易结束 – 空行
output_lines.append("")

这个脚本逻辑执行以下操作:

  • 将日期格式化为 Beancount 的 YYYY-MM-DD 格式。

  • 使用收款人 (Name) 和备注 (Memo) 作为交易的叙述。例如: 2020-05-01 * "ACME Corp" "Invoice payment" (如果没有收款人,你可以使用 QuickBooks 的交易类型或留空收款人引号)。

  • 如果存在参考编号(支票号、发票号等),则添加一个 number 元数据。

  • 迭代每一条分录行:

    • 使用字典 account_map(从会计科目表步骤中填充)将 QuickBooks 账户名映射到 Beancount 账户。
    • 确定金额。根据你的导出文件,可能有一个金额列(带有正/负值)或独立的借方和贷方列。上面的代码处理了这两种情况。它确保贷方表示为负金额,因为在 Beancount 中,每个记账都使用带符号的单个数字。
    • 附加货币(除非存在不同的货币列,否则假设为 USD)。
    • 用账户、金额和带有行备注的注释写入 Beancount 记账行。例如: Assets:Checking 500.00 USD ; Deposit Income:Sales -500.00 USD ; Deposit 这反映了一笔 500 美元的存款(从收入到支票账户)。
  • 列出所有分录后,用一个空行分隔交易。

多币种处理: 如果你的 QuickBooks 数据涉及多种货币,请在每个记账上包含货币代码(如上所示)。确保外币账户以该货币开设。例如,如果你有一个欧元银行账户,你会输出 open Assets:Bank:Checking EUR,并且该账户中的交易将使用 EUR。Beancount 支持多币种账本并会跟踪隐式转换,但如果你想在报表中转换为基础货币,可能需要添加汇率的价格条目。还建议在 Beancount 文件的顶部声明你的主要经营货币(例如,option "operating_currency" "USD")。

运行转换: 保存 Python 脚本(例如,qb_to_beancount.py)并在你导出的文件上运行它。它应该会生成一个包含所有账户和交易的 .beancount 文件。

2.2 处理边缘情况和数据清理

在转换过程中,请注意以下常见的陷阱以及如何解决它们:

  • 账户名称不匹配: QuickBooks 的账户名称可能与 Beancount 的层级名称冲突。例如,QuickBooks 可能有两个不同的父账户,每个都有一个名为 "Insurance" 的子账户。在 Beancount 中,Expenses:Insurance 必须是唯一的。在导出前通过重命名其中一个(例如,“Insurance-Vehicle” vs “Insurance-Health”)来解决此问题,或者在脚本中将它们映射到唯一的 Beancount 账户。一致的命名约定(无特殊字符,并使用层级结构)将省去很多麻烦。如果需要,使用重映射文件的方法:维护一个旧名称 → 新 Beancount 名称的 CSV 或字典,并在转换期间应用它(我们的示例代码使用了一个 account_map,并且可以从文件中加载覆盖项)。

  • 日期和格式: 确保所有日期格式一致。上面的脚本将 M/D/Y 规范化为 ISO 格式。另外,如果你的五年跨度跨越了年终,请注意财政年度与日历年度的问题。Beancount 不关心财政年度的界限,但你以后可能为了方便而按年拆分文件。

  • 数值精度: QuickBooks 处理货币到分,所以以分为单位工作通常没问题。理想情况下,CSV 中的所有金额都应有两位小数。如果任何金额变成了整数(没有小数)或带有逗号/括号(表示负数),请在脚本中清理它们(去除逗号,将 (100.00) 转换为 -100.00 等)。如果按照指示正确导出 CSV,应该已经避免了这些格式问题。

  • 负数和符号: QuickBooks 报表有时将负数显示为 -100.00(100.00),甚至在某些 Excel 导出中显示为 --100.00。清理步骤应该处理这些情况。确保每笔交易的借贷方总和为零。Beancount 会强制执行这一点(如果不平衡,导入时会抛出错误)。

  • 交易重复: 如果你必须分批导出交易(例如,逐年或逐账户),请小心合并它们,不要重叠。检查一年的第一笔交易是否也是前一批的最后一笔,等等。在边界处很容易意外复制一些交易。如果你怀疑有重复,可以按日期对最终的 Beancount 条目进行排序并查找相同的条目,或者使用 Beancount 的唯一交易标签来捕获它们。一种策略是将 QuickBooks 交易号作为元数据包含进来(例如,使用 Trans # 或发票号作为 txn 标签或 quickbooks_id 元数据),然后确保这些 ID 没有重复。

  • 不平衡的分录 / 暂记账户: QuickBooks 可能有奇怪的情况,比如一笔交易有不平衡,QuickBooks 会自动将其调整到“期初余额权益”或“留存收益”账户。例如,在设置初始账户余额时,QuickBooks 通常会将差额记入一个权益账户。这些会出现在导出的交易中。Beancount 将要求显式平衡。你可能需要引入一个用于期初余额的权益账户(通常是 Equity:Opening-Balances)来镜像 QuickBooks。在账本的第一天有一个建立所有账户期初余额的条目是很好的做法(见阶段五)。

  • 多币种边缘情况: 如果使用多币种,QuickBooks 的导出可能会以本国货币或其原生货币列出所有金额。理想情况下,获取每个账户的原生货币数据(QuickBooks 在线版的报表通常会这样做)。在 Beancount 中,每个记账都带有一个货币。如果 QuickBooks 提供了汇率或本国货币换算,你可以忽略这些,并依赖 Beancount 的价格条目。如果 QuickBooks 没有导出汇率,你可能需要手动添加关键日期的价格记录(例如,使用 Beancount 的 price 指令)以匹配估值。然而,对于基本的账本完整性,只要交易以其原始货币平衡就足够了——除非你想要相同的报告,否则不必明确记录未实现损益。

  • 应收账款 / 应付账款: QuickBooks 跟踪发票和账单的详细信息(到期日、支付状态等),这些在纯账本中不会完全转移。你会得到应收(A/R)和应付(A/P)的交易(发票增加 A/R,付款减少 A/R 等),但不会有发票文件或每个发票的客户余额。因此,迁移后,你应该验证 Beancount 中的 A/R 和 A/P 账户余额是否等于 QuickBooks 中客户/供应商的未结余额。如果你需要跟踪发票,可以使用 Beancount 的元数据(例如,包含一个 invoice 标签或链接)。QuickBooks 的发票号应该已经通过 NumMemo 字段导出了——我们的脚本将 Num 保留为交易元数据中的 number: "..."

  • 不活动或已关闭的账户: IIF 导出文件可能包含不活动的账户(如果你选择包含它们)。导入它们没问题(如果它们真的不活动,它们将没有交易并且余额为零)。你可以在最后一笔交易日期之后,用 close 指令在 Beancount 中将它们标记为已关闭。这可以使你的账本保持整洁。例如: 2023-12-31 close Expenses:OldAccount ; migrated after migration 这是可选的,主要是为了整洁。

通过仔细清理和映射上述数据,你将拥有一个在结构上与你的 QuickBooks 数据相匹配的 Beancount 账本文件。下一步是验证它在数值上也与 QuickBooks 相匹配。


阶段三:数据验证和对账

验证是会计数据迁移中至关重要的一步。我们需要确保 Beancount 账本与 QuickBooks 账簿精确到每一分钱。可以使用多种策略和工具:

3.1 试算平衡表对账

试算平衡表报告列出了所有账户的期末余额(带有借方和贷方或正/负标记),并且净额应为零。在两个系统中运行同一日期的试算平衡表是确认整体准确性的最快方法。

  • 在 QuickBooks 中: 运行最后一年的最后一天(例如,2023年12月31日)的试算平衡表 (Trial Balance) 报告。这份报告显示了每个账户的余额。导出它或记下关键数字。

  • 在 Beancount 中: 使用 Beancount 的报告功能生成试算平衡表。一个简单的方法是通过命令行:

    bean-report migrated.beancount balances

    balances 报告就是一个试算平衡表,列出了所有账户及其余额。你也可以在 Fava(Beancount 的网页界面)中打开文件,并查看 BalancesBalance Sheet 部分。Beancount 中的每个账户余额都应与 QuickBooks 的试算平衡表相匹配。例如,如果 QuickBooks 显示应收账款 = 5,000,那么BeancountAssets:AccountsReceivable账户总额应为5,000*,那么 Beancount 的 `Assets:Accounts Receivable` 账户总额应为 5,000(借方)。如果销售收入 = 200,000,那么Beancount中的Income:Sales应显示200,000*,那么 Beancount 中的 `Income:Sales` 应显示 200,000(贷方,如果使用将贷方显示为负数的试算平衡表,可能会显示为 -200,000)。

如果存在差异,找出它们:

  • 检查是否整个账户丢失或多余(我们是否忘记了一个账户,或者包含了一个在迁移期之前已经关闭的账户?)。
  • 如果余额不对,深入检查:QuickBooks 可以为该账户运行账户快速报告 (Account QuickReport) 或分类账明细,你可以将其与 Beancount 中该账户的登记簿 (bean-report migrated.beancount register -a AccountName) 进行比较。差异有时来自丢失的交易或重复的交易。

同时验证 Beancount 试算平衡表中所有账户的总和为零(它会打印一个总计,应该为零或非常接近零)。Beancount 强制执行复式记账,所以如果你有任何不为零的不平衡,意味着资产减去负债加权益不为零,表明存在问题(QuickBooks 通常也不允许这种情况,但如果某些数据丢失了可能会发生)。

3.2 账户余额比较

除了试算平衡表,你还可以比较特定的财务报表:

  • 资产负债表: 运行 QuickBooks 最终日期的资产负债表和 Beancount 的资产负债表 (bean-report migrated.beancount balsheet)。这与试算平衡表类似,但按资产、负债、权益组织。数字应该按类别对齐。为了更精细的检查,比较主要账户的总额:现金、应收账款、固定资产、应付账款、权益等。

  • 利润表 (损益表): 在 QuickBooks 和 Beancount 中运行五年期间(或逐年)的利润表 (bean-report migrated.beancount income 用于整个期间的利润表)。Beancount 的净收入应与 QuickBooks 每个期间的净收入相等。如果你迁移了所有五年,累计净收入应该匹配。你还可以比较单个收入和费用总额,以确保没有类别被遗漏或重复计算。

  • 随机抽样交易: 随机挑选几笔交易(特别是从每年和每个主要账户中挑选)并验证它们是否正确迁移。例如,在 QuickBooks 中找到 3 年前的一张发票,然后在 Beancount 文件中搜索其金额或备注(因为所有交易都是文本,你可以在文本编辑器中打开 .beancount 文件或使用搜索工具)。检查日期、金额和账户是否匹配。这有助于捕捉任何日期格式问题或账户映射错误。

3.3 自动化完整性检查

利用 Beancount 自身的验证工具:

  • bean-check: 运行 bean-check migrated.beancount。这将解析文件并报告任何语法或平衡错误。如果脚本遗漏了像未开设的账户或不平衡的交易之类的问题,bean-check 会标记出来。干净的通过(没有输出)意味着文件至少在内部是一致的。

  • 余额断言: 你可以在账本中为关键账户添加明确的余额断言作为额外检查。例如,如果你知道某个日期银行账户的余额,添加一行: 2023-12-31 balance Assets:Bank:Checking 10000.00 USD 然后 bean-check 将确保在该日期,账本中的余额确实是 $10,000。这是可选的,但对于非常重要的账户很有用。你可以从 QuickBooks 获取期末余额(例如,每年年底),并在 Beancount 文件中进行断言。如果任何断言失败,Beancount 将报告差异。

  • 试算平衡表滚动检查: 如果你愿意,可以进行逐期检查。对于每一年,比较净变化。例如,QuickBooks 2020 年的净收入与 Beancount 2020 年的净收入,等等,以确保每年都正确地结转到权益中(QuickBooks 在每个新年自动将净收入滚入留存收益;在 Beancount 中你只会看到累计的权益)。如果你看到差异,这可能表明特定年份的数据存在问题。

  • 交易计数和重复: 计算 QuickBooks 与 Beancount 中的交易数量。QuickBooks 不容易直接显示计数,但你可以通过计算 CSV 中的行数(每个交易标题与分录)来估计。在 Beancount 中,一个快速的方法是计算文件中 txn* " 的出现次数。它们应该等于或略高于 QuickBooks(如果你添加了期初余额交易或调整)。显著的不匹配意味着某些内容可能被遗漏或重复了。我们使用元数据中的唯一 ID 可以提供帮助:如果你怀疑有重复,可以在 Beancount 文件中搜索相同的支票号或发票号是否出现了两次。

  • 对账状态: 我们在脚本中根据 QuickBooks 的已清算状态包含了一个 rec: "y""n" 的元数据(在示例中为 rec)。这不是一个标准的 Beancount 功能(Beancount 不像 Ledger 那样跟踪已清算/待处理状态),但它可以作为有用的元数据。你可能需要验证在 QuickBooks 中所有已对账的交易都存在。最终,在 Beancount 中重新对账银行账户(使用你的银行对账单)可能是证明没有任何遗漏的最终证据。

通过执行这些验证,你可以建立对迁移保留了数据的信心。在这个阶段要花足够的时间——现在修复异常比几个月后依赖这些账簿时要容易得多。如果验证失败,常见问题包括:账户的期初余额丢失、交易日期超出范围,或条目的符号反转。一旦确定,这些都是可以修复的。


阶段四:提交到 Beancount 账本

在清理和验证之后,是时候将数据正式化到你的 Beancount 账本结构中了。“提交”在这里既指最终确定账本文件,也可能指将它们检入版本控制系统以备审计。

4.1 组织账本文件和配置

决定如何组织 Beancount 账本文件。对于五年的数据,你可以将所有内容保存在一个文件中,或者按年份或类别拆分。一个常见、清晰的结构是:

  • 主账本文件: 例如,ledger.beancount – 这是可以 include 其他文件的入口点。它可能包含全局选项,然后包含年度文件。
  • 账户文件: 定义会计科目表和期初余额。例如,accounts.beancount 包含所有 open 指令(由脚本生成)。你也可以在这里列出商品(货币)。
  • 交易文件: 每年一个,例如 2019.beancount, 2020.beancount 等,包含该年的交易。这使每个文件的大小易于管理,并允许你在需要时专注于某一年。或者,你可以按实体或账户拆分,但按时间拆分对于财务数据来说很直接。

主文件示例:

option "title" "我的商业账本"
option "operating_currency" "USD"

include "accounts.beancount"
include "2019.beancount"
include "2020.beancount"
...
include "2023.beancount"

这样,当你运行报告时,所有数据都会被汇总,但你保持了秩序。

Beancount 不要求多个文件——你可以只有一个大文件——但上述结构提高了清晰度和版本控制。根据 Beancount 的最佳实践,使用清晰的节标题并按逻辑对相关条目进行分组是很好的做法。

4.2 设置期初余额和权益

如果你的迁移不是从绝对零开始,你需要处理期初余额。两种情况:

  • 从零开始的账簿: 如果五年期始于业务成立之初(例如,你从 2019 年 1 月开始使用 QuickBooks,所有账户除了初始权益外都为零),那么你可能不需要一个单独的期初余额交易。2019 年的第一批交易(如向银行账户注入初始资金)将自然地建立期初余额。只需确保任何初始资本之前的留存收益都通过权益交易入账。

  • 中途开始的账簿(部分历史): 如果你更早开始使用 QuickBooks,而 2019 年是一个中点,那么截至 2019 年 1 月 1 日,每个账户都有一个结转余额。QuickBooks 会将这些作为期初余额或留存收益。在 Beancount 中,通常的做法是在你的开始日期前一天创建一个期初余额条目:

    • 使用一个名为 Equity:Opening-Balances(或类似名称)的权益账户来抵消所有期初金额的总和。
    • 例如:如果在 2018-12-31,现金为 10,000,应收账款为10,000,应收账款为 5,000,应付账款为 3,000(贷方),你会写一笔交易:20181231"OpeningBalances"Assets:Cash10000.00USDAssets:AccountsReceivable5000.00USDLiabilities:AccountsPayable3000.00USDEquity:OpeningBalances12000.00USD这使得OpeningBalances账户的余额为负数总和(–3,000(贷方),你会写一笔交易: `2018-12-31 * "Opening Balances"` ` Assets:Cash 10000.00 USD ` ` Assets:Accounts Receivable 5000.00 USD ` ` Liabilities:Accounts Payable -3000.00 USD ` ` Equity:Opening-Balances -12000.00 USD ` 这使得 `Opening-Balances` 账户的余额为负数总和(–12k),从而平衡了该条目。现在,所有资产/负债账户在 2019 年初都具有正确的余额。这应该与 QuickBooks 的任何“留存收益”或结转余额相对应。
    • 或者,使用 Beancount 的 padbalance 指令:对于每个账户,你可以从 Opening-Balances pad 它,并断言其余额。这是一种更自动化的方式。例如: 2018-12-31 pad Assets:Cash Equity:Opening-Balances 2018-12-31 balance Assets:Cash 10000.00 USD 这告诉 Beancount 插入任何必要的条目(到 Opening-Balances),以便现金在该日期等于 10000 USD。对每个账户都这样做。结果类似,但像第一种方法那样写一个明确的交易也很直接。
  • 留存收益: QuickBooks 不会明确导出一笔“留存收益”交易——它只是计算它。迁移后,你可能会注意到 Equity:Retained Earnings 是零,如果你没有创建它的话。在 Beancount 中,留存收益只是前几年的利润。你可以选择创建一个留存收益账户,并在每个新年的第一天将以前的利润转入其中,或者干脆让权益成为所有收入/费用的总和(这在报告的权益部分下显示)。为了透明度,一些用户每年都会做结账分录。这是可选的,主要用于展示。由于我们迁移了所有交易,如果你按年运行报告,每年的利润自然会累计。

  • 比较检查: 设置期初余额后,在开始日期运行资产负债表,以确保一切正确(它应该显示那些期初余额与期初权益相抵为零)。

4.3 最终确定和版本控制

现在数据已是 Beancount 格式并已结构化,明智的做法是将文件提交到版本控制仓库(例如,git)。对账本的每次更改都可以被跟踪,并且你有一个所有修改的审计追踪。这是纯文本会计的一个主要优势。例如,在 QuickBooks 中,更改可能不容易进行差异比较,但在 Beancount 中,你可以看到逐行的差异。正如一些用户指出的,使用 Beancount 你可以获得透明度以及在需要时恢复更改的能力——每个条目都可以追溯到变更历史。

考虑将这次初始迁移的提交标记为 v1.0 或类似标记,这样你就知道它代表了从 QuickBooks 导入时的账簿状态。今后,你将直接在 Beancount 中输入新交易(或从银行源导入等),并且你可以使用常规的软件开发实践(每月或每天提交,使用分支进行实验等)。

设置 Fava 或其他工具: Fava 是 Beancount 的一个 Web 界面,可以方便地查看报告。提交后,运行 fava ledger.beancount 来浏览财务报表,并最后一次与你的 QuickBooks 报告进行比较。你可能会在 UI 中更容易发现微小的差异(例如,一个本应为零但显示微小余额的账户表明有遗漏的结账分录或一个孤立的交易)。

命名约定和一致性: 你现在拥有完全的控制权,所以要确保一致性:

  • 所有账户都应该有清晰的名称,以大写的类别名称开头(Assets, Liabilities 等)。如果任何名称看起来奇怪(例如,由于 QuickBooks 的大小写不匹配导致的 Assets:assets:SomeAccount),在账户文件中重命名它们并更新交易(对文件进行快速查找/替换可以做到这一点,或者使用 Beancount 的 bean-format 或编辑器的多光标功能)。
  • 商品符号(货币代码)应该一致。对于美元,到处都使用 USD(而不是 $US$)。对于其他货币,使用标准代码(EUR, GBP 等)。这种一致性对于 Beancount 的价格查找和报告很重要。
  • 移除任何可能已创建的临时或虚拟账户(例如,如果你在脚本中使用 Expenses:Miscellaneous 作为未知账户的通用账户,尝试通过正确映射所有账户来消除它们)。

关闭 QuickBooks: 此时,你应该在 Beancount 中有与 QuickBooks 相匹配的并行账簿。有些人选择在短时间内并行运行两个系统,以确保没有遗漏。但如果验证是可靠的,你可以“关闭” QuickBooks 账簿:

  • 如果这是一个公司环境,考虑导出所有 QuickBooks 源文件(发票、账单、收据)作为记录,因为除非你手动附加,否则它们不会存在于 Beancount 中。
  • 保留 QuickBooks 数据的备份(公司文件和导出文件)。
  • 从今往后,将 Beancount 账本作为主要的记录系统。

通过将数据提交到 Beancount 账本,你已经完成了迁移流程。最后一步是进行审计并展示财务报表的一致性,以让你自己(以及任何利益相关者或审计师)满意迁移是成功的。


阶段五:迁移后审计和示例

为了说明迁移的成功,准备一份财务报表的前后对比,并可能提供交易的差异对比。这为账簿的一致性提供了证据。

5.1 验证财务报表

从 QuickBooks 和 Beancount 中生成相同日期的关键财务报告并进行比较:

  • 截至 2023 年 12 月 31 日的资产负债表: 逐行比较资产、负债和权益总额。它们应该匹配。例如,如果 QuickBooks 显示总资产 = 150,000总负债+权益=150,000**,** 总负债 + 权益 = 150,000,那么 Beancount 的资产负债表也应显示相同的总额。如果你对账户结构做了微调(比如合并了一些子账户),在比较时要考虑到这一点,或者分解到下一级以确保总和相等。

  • 2019–2023 年利润表: 确保每年(或整个期间)的总收入、总费用和净利润是相同的。如果 QuickBooks 在报告上进行了一些四舍五入,可能会出现微小差异,但交易通常精确到分,所以净利润应该是精确的。如果某年的利润不同,深入研究该年的数据——这通常是该时期有遗漏或重复条目的迹象。

  • 试算平衡表差异: 如果可能,创建一个电子表格,列出每个账户以及来自 QuickBooks 和 Beancount 的余额。由于我们期望它们匹配,这可能是一个全为零的差异列。这本质上是我们讨论过的试算平衡表交叉检查,但把它写出来有助于记录。

5.2 示例比较(迁移前 vs 迁移后)

下面是一个示例片段,展示了数据的一致性。假设我们 2023 年 12 月 31 日的 QuickBooks 试算平衡表是:

账户QuickBooks 余额 (2023年12月31日)
资产 (Assets)
Assets:Bank:Checking$12,500.00 (借方)
Assets:Accounts Receivable$3,200.00 (借方)
负债 (Liabilities)
Liabilities:Credit Card$-1,200.00 (贷方)
Liabilities:Loans Payable$-5,000.00 (贷方)
权益 (Equity)
Equity:Opening-Balances$-7,500.00 (贷方)
Equity:Retained Earnings$-2,000.00 (贷方)
Equity:Current Year Profit$0.00

在 Beancount 中,导入并记入所有截至 2023 年的交易后,bean-report balances(试算平衡表)输出:

账户Beancount 余额 (2023年12月31日)
资产 (Assets)
Assets:Bank:Checking12,500.00 USD (借方)
Assets:Accounts Receivable3,200.00 USD (借方)
负债 (Liabilities)
Liabilities:Credit Card-1,200.00 USD (贷方)
Liabilities:Loans Payable-5,000.00 USD (贷方)
权益 (Equity)
Equity:Opening-Balances-7,500.00 USD (贷方)
Equity:Retained Earnings-2,000.00 USD (贷方)
Equity:Profit (2019-2023)0.00 USD

(注意:权益部分的结构可能不同;关键是总额一致。在这里,Beancount 中的“利润 (2019-2023)”扮演了当年利润/留存收益合并的角色,显示为零是因为利润已结转至留存收益。)

如上所示,每个账户都精确到分。借方总额等于贷方总额。

此外,如果我们运行 2023 年的利润表:

  • QuickBooks: 收入 50,000,费用50,000,费用 48,000,净利润 $2,000。
  • Beancount: 收入 50,000,费用50,000,费用 48,000,净利润 $2,000(然后结转到留存收益或出现在年终资产负债表的权益部分)。

如果需要,你可以创建交易的差异对比,但由于 QuickBooks 数据不是账本格式,依赖报表更有效。可以将 QuickBooks CSV 和 Beancount 交易按日期排序,并比较关键字段作为最后检查(这可以在 Excel 中或用脚本完成)。然而,鉴于我们信任之前的验证,财务报表检查通常就足够了。

5.3 审计技巧

  • 如果审计师或利益相关者需要保证,请并排展示迁移前后的财务报表Beancount 的透明度实际上可以简化审计,因为你可以快速地从报表上的每个数字追溯到源条目(特别是使用 Fava 的下钻功能)。
  • 保留 QuickBooks 备份和导出的 CSV 文件作为审计追踪的一部分。记录迁移过程中所做的任何调整(例如,“为保持一致性将账户 X 重命名为 Y”或“为清晰起见将交易 Z 分为两个条目”,如果你做了这样的更改)。
  • 从今往后,在 Beancount 中实施定期检查。例如,每月对账银行账户并对其期末余额进行断言,有助于捕捉任何数据问题或录入错误。迁移提供了一个良好的基线;在新系统中保持纪律将确保持续的准确性。

最后,庆祝迁移完成:你已经成功地将五年的会计数据从 QuickBooks 转移到了 Beancount。数据现在以轻量级、版本控制的文本格式存在,具有完整的复式记账完整性。你导出了数据,用 Python 脚本转换了它,通过试算平衡表和报告验证了其完整性,并将其提交到一个组织良好的 Beancount 账本中。这个全面的过程确保了 Beancount 账本是你在五年期间 QuickBooks 账簿的准确、忠实的复制品,为你未来的精简会计工作奠定了基础。