使用 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:AccountsReceivable
中 INV-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)。
后续步骤
准备好控制你的开票了吗? 以下是开始的方法。
- 下载模板并使用它创建你的下一个真实发票,确保使用连续的发票编号。
- 将你发送的 PDF存储在专用文件夹中,例如
docs/invoices/
,并在你的 Beancount 交易中使用link:
元数据键来引用它们。 - 保存
open-invoices.sql
查询并将其作为你 每周财务审查的一部分运行。
纯文本会计并不意味着放弃完善或控制——它只是意味着数据库是可 grep
的。 使用简单的模板和上面的代码片段,你将更快地获得付款_并且_保持你的账簿整洁。