请查收你的「开年变富攻略」:开发者如何借助开源工具,科学记账?

2,741 阅读13分钟

写在前面: 面对全面放开后多样的消费机会,开发者们如何在保障品质生活的同时,借助开源工具,全面、科学地规划和管理个人财务,把握资金动向,避开消费陷阱?

LigaAI 特邀我司 Nerd4me 大佬分享其个人财务管理经验,系列共分「概念篇」和「实战篇」。本篇「实战篇」,将展开介绍开发者如何使用 Beancount 系统且便捷地记账。

Beancount 是一个基于纯文本的开源记账软件,提供了一系列开箱即用的命令行工具,以及一套简洁、实用且美观的 Web UI。

其核心记账逻辑是「复式记账法」,即每一笔交易至少关联两个交易账户,一借一贷,数额相等。特别的是, 复式记账法规定「收入为负,支出为正」 —— 在《「钞能力养成指北」前传》中,我们也详细解释了这点,大家可以按需补课。

👉新手指南:Why Beancount?

市面上有非常多成熟、知名的记账工具,为什么我仍强烈推荐使用 Beancount?出于以下几点考虑:

  1. Beancount 采用改良版的复式记账方案,「正负」代替「借贷」 对非会计专业的朋友更友好;

  2. 可直接在本地运行。相比基于云端的工具,数据安全更有保障,无需担心个人账务泄漏;

  3. 纯文本文件管理账目,便于记录和存储。 基于 Beancount 语法生成的文件,很容易阅读;

  4. 提供完整的命令行工具集和可视化工具 Fava(内含大量财报模板),支持基于类 SQL 查询,可轻松生成各种复杂的报表数据;

  5. 账本既是用户的输入文件,也是软件的「数据库」,可实现数据和工具的「无痛搬家」

Beancount 是 Ledger-Like 家族的杰出成员。对比背靠 C++ 的 Ledger,基于 Python 的 Beancount 应用轻便,新增插件或二次开发更简单;多货币支持等丰富而强大的功能,能够很好地覆盖各种记账、查账场景。

事实上,Beancount 并不知道什么是「货币」。它只是记录了「通货 Commodity」的变化,而通货完全由用户定义。 因此,Beancount 可以记录含货币在内任何东西的变化,如年假天数、股票、航空里程、信用卡积分……

当然,也可以用来数豆子——这也是「Beancount」名字的由来 >A<

👉 英勇黄铜:基本环境搭建

迈出「Beancount 记账」的第一步,需要安装 Python3 环境和对应包。

pip install beancount fava

使用下列命令,生成一个官方提供的示例。

bean-example > example.beancount

通过 fava 命令运行 Web UI 。默认情况下的 Web UI 会运行在 http://localhost:5000 中。

fava -H 0.0.0.0 example.beancount

👉 不屈白银:Beancount 语法入门

环境搭建后,我们需要制作账本来承载账目信息。Beancount 作者在 Beancount User's Manual 中提供了非常详尽的使用说明,大家可以根据实际需求自行创建。

下面以《「钞能力养成指北」前传》中「老王煎饼摊」为例,逐步演示如何使用 Beancount 编写账本并制成报表。

1. 制作账本

新建一个纯文本文件并保存为 laowang.bean。在任意文本编辑器打开,只需简单两步就能完成账本内容的编写。

第一步:设立交易账户

使用  open  命令设立交易账户,语法结构为开户时间 open 账户类型:账户名称 货币类型;备注

其中,开户时间应早于该账户关联的首笔交易产生的时间;同时,在复式记账法中,交易账户分为五大类型:

  • Assets - 资产类账户:现金、存款、基金、股票、房子、车子、借出账款等;

  • Liabilities - 负债类账户:信用卡、贷款、花呗、向他人借款等;

  • Income - 收入类账户:工资、奖金、专利、投资收益等;

  • Expenses - 费用类账户:衣食住行等一切花销、过年发出的红包等;

  • Equity - 权益类账户:记账前已有的资产或负债,一般在账户初始化时设置。

1970-01-01 open Income:Sales CNY
1970-01-01 open Assets:Bank:Saving:ICBC CNY
1970-01-01 open Assets:Fixed CNY ;固定资产
1970-01-01 open Liabilities:CreditCard:ICBC CNY
1970-01-01 open Expenses:Food CNY

第二步:编写交易记录

Beancount 是复式记账工具,其账目分录至少包含三行信息:交易详情、支出详情和收入详情。

交易详情记录了交易时间、收款人信息和交易备注,格式为 YYYY-MM-DD */! "" "" 

  • 「 */! 」为对账标识符: * 表示该交易已确认,! 表示该交易存疑/待确认。
  • 双引号中的为选填内容,分别记录「收款人 Payee」和「交易备注 Narration」。

支出/收入详情记录出/进账的账户名称、交易数额和货币类型,出账为负,进账为正,正负金额相加为零。

2023-01-01 * "xx公司" "购买设备"
  Assets:Bank:Saving:ICBC      -1,000.00 CNY
  Assets:Fixed                  1,000.00 CNY

2023-01-01 * "采购食材"
  Liabilities:CreditCard:ICBC   -500.00 CNY
  Expenses:Food                  500.00 CNY

把「老王煎饼摊」的账本补充完整,就会得到下面这个 laowang.bean 文件。

1970-01-01 open Income:Sales CNY
1970-01-01 open Assets:Bank:Saving:ICBC CNY
1970-01-01 open Assets:Fixed CNY ;固定资产
1970-01-01 open Liabilities:CreditCard:ICBC CNY
1970-01-01 open Expenses:Food CNY

2023-01-01 * "xx公司" "购买设备"
  Assets:Bank:Saving:ICBC      -1,000.00 CNY
  Assets:Fixed                  1,000.00 CNY

2023-01-01 * "采购食材"
  Liabilities:CreditCard:ICBC   -500.00 CNY
  Expenses:Food                  500.00 CNY

2023-01-02 * "煎饼销售收入"
  Income:Sales                -1,000.00 CNY
  Assets:Bank:Saving:ICBC      1,000.00 CNY

2023-01-02 * "质量问题食材退货"
  Expenses:Food                 -100.00 CNY
  Liabilities:CreditCard:ICBC    100.00 CNY

2. 生成财务报表

使用 Beancount 命令行工具集中的 bean-report 命令,可以实现各类财务报表的自动生成。

比如, income 子命令能生成损益表,balsheet 可以统计资产负债情况,balances 用于查询各账户余额等。

(BEANCOUNT) bean-report laowang.bean balances
Assets:Bank:Saving:ICBC
Assets:Fixed                   1000.00 CNY
Equity
Expenses:Food                   400.00 CNY
Income:Sales                  -1000.00 CNY
Liabilities:CreditCard:ICBC    -400.00 CNY

账户余额表指出,老王持有 1,000 元的固定资产、在食材上花费 400 元、煎饼营业收入 1,000 元、信用卡欠款 400 元。

对许多非技术背景的朋友来说,用命令行呈现的数据有点不太好阅读。没关系,Beancount 自己会出手:Beancount 为我们提供了一个可视化工具 Fava

安装 Fava 后,使用 fava laowang.bean 命令启动 Web UI 服务。在浏览器中打开 http://localhost:5000/,就可以获得表格式的报表数据。

图片

图片

👉 荣耀黄金:进阶场景说明

在现实生活中,除了「一对一」交易,我们还会遇到很多涉及多个账户的「一对多」和「多对多」的情况。下面几个场景展示了 Beancount 和复式记账法在处理复杂交易方面的优势。

场景 1 :发工资

应聘谈薪,我们关心「税前工资」和「到手工资」。那么,每月发放的工资、奖金,缴纳的五险一金和个人所得税等费用,在 Beancount 中应该如何入账呢?

2023-01-10 * "Some Company" "💰工资2022-12"
  Income:SomeCompany:Salary           -20,000.00 CNY ;应发工资
  Income:SomeCompany:Benefits            -500.00 CNY ;节日福利
  Income:SomeCompany:HousingFund       -2,000.00 CNY ;住房公积金单位扣除
  Assets:Government:HousingFund         4,000.00 CNY ;住房公积金缴纳
  Expenses:Government:SocialSecurity    1,500.00 CNY ;社保缴纳
  Expenses:Government:IncomeTax         3,000.00 CNY ;个税缴纳
  Assets:Bank:Saving:ICBC              14,000.00 CNY ;实发工资

不难看出,复式记账法的优势之一是能够清晰地展示同一笔交易中,资金在各个账户之间的流动关系,反映资金运动的来龙去脉。

场景 2 :记录房产

对于房产、车辆等固定资产,我们不只关心其购入时的价值,也同样在乎其后续的升/贬值情况,即当前市场估值

Beancount 不预先定义任何货币,我们可以创建人民币 CNY 的变种货币 CNY.UNVEST,赋予房子一个人民币变种价格(即估值价格)

这样,在以人民币 CNY 展示总资产时,我们既能在价格页查看房子的当前市值估值,也不会影响总资产的统计。

;创建房产货币
2018-06-01 commodity HOUSE.ABC
  name: "房产名称"
2018-06-01 open Assets:Property:CS:ABC HOUSE.ABC

;房产购买
2018-06-01 * "XX地产" "房产名称"
  Assets:Property:CS:ABC                        1 HOUSE.ABC {2,000,000.00 CNY} ;房产购买价格
  Assets:Bank:Saving:ICBC              600,000.00 CNY ;首付款
  Liabilities:Bank:BOC:MortgageLoan  1,400,000.00 CNY ;抵押贷款

;房产价格
2018-06-01 price HOUSE.ABC 2,000,000.00 CNY ;买入成本
2018-06-01 price HOUSE.ABC 2,000,000.00 CNY.UNVEST ;估值价格
2023-01-17 price HOUSE.ABC 2,500,000.00 CNY.UNVEST ;估值价格

场景 3 :AA 制消费分摊

AA 制的费用分摊、信用卡分期还款等交易记账是典型的「一对多」场景。

小红和小明外出吃饭一共花费 500 元,由小红先行支付;小明几天后想起,将 AA 的费用转账还给小红。在小红的账本中,这笔钱应该这样记录:

2023-01-13 * "xx 饭店" "和小明吃饭"
  Assets:VA:Wechat              -500.00 CNY ;微信零钱付款
  Expenses:Food:DiningOut        250.00 CNY ;AA我(小红)的一半
  Assets:Receivables:Xiao-Ming   250.00 CNY ;AA小明的一半

2023-01-17 * "小明" "AA吃饭收款"
  Assets:VA:Wechat               250.00 CNY
  Assets:Receivables:Xiao-Ming  -250.00 CNY

场景 4 :货币转换

出入境限制全面放开,许多好友也都选择出国游玩散心。在消费记账时,Beancount 如何处理不同货币之间的汇率转化关系?

在登记交易时,使用 @@ 即可连接两种互相转换的货币。本例中,信用卡支出的 650 元人民币正是由 100 美元转换而来。

2023-01-17 * "在免税店买东西"
 Assets:Cash                                 -200.00 USD ;现金支付
 Liabilities:CreditCard:ICBC                 -650.00 CNY @@ 100.00 USD ;信用卡付款
 Expenses:Clothing:Pants                     +150.00 USD
 Expenses:Clothing:Shoes                     +150.00 USD

场景 5 :使用 DSL 进行复杂查询

除了 bean-report 命令外,Beancount 还提供 bean-query 工具,支持 SQL 语句查询,以满足更复杂的数据统计。感兴趣的朋友可以在 Beancount – Query Language 文档中了解。

这里分享一下让 Beancount 回答「我都在哪些加油站加过几次油」的操作指令。

图片

👉 超凡大师:最佳实践分享

看到这里的朋友们,恭喜你们已经学会了 Beancount 复式记账的常用语法和操作。它们可以满足生活中绝大多数消费和交易的记账需求。下面分享的是一些个人实践的经验总结,希望能更好地帮你开启「Beancount 之旅」。

1. 账本编辑器的选择

我选择 VSCode 作为账本文件编辑器,搭配 Lencerf/vscode-beancount 插件一起使用,可以自动为 .bean 或者 .beancount 文件加上语法高亮、补全账户名,还可以实现金额数据的自动对齐。

具体的配置操作请查看作者在 Github 上提供的帮助文档了解。

2. 账户开户日期的设立

前面提到,交易账户的开设日期应早于该账户首笔交易产生的时间。这里也补充一些比较有意思的开户事件,供诸位参考。

  • Expenses 账户可以使用自己的出生日期作为开户日期;
  • Income 账户可以按来源分类后再选择日期,如 Income:SomeCompany:Salary 的开户时间是该公司的入职日期;
  • Assets 和 Liabilities 账户中的借/贷记卡的开设日期,与银行的开户日期保持一致。

3. 分割账本文件结构

记账是一个长期习惯,但是随着时间累积,账本文件越变越大,只在一个文件中编写和记录就会变得极其不便。

因此,在创建账本时,我们可以提前规划账本分类,使用 Beancount 的 include 语法对账本进行结构分割。这样就可以在一个 Beancount 文件中包含其他的文件,就像下面这样:

.
├── 2022
│   ├── 09.bean
│   ├── 10.bean
│   ├── 11.bean
│   ├── 12.bean
│   ├── __index.bean
│   ├── creditcard.bean
│   ├── event.bean
│   ├── forecast.bean
│   ├── income.bean
│   ├── loan.bean
│   └── transfer.bean
├── 2023
│   ├── 01.bean
│   ├── __index.bean
│   ├── forecast.bean
│   ├── income.bean
│   ├── insurance.bean
│   ├── loan.bean
│   └── transfer.bean
├── account
│   ├── __index.bean
│   ├── assets.bean
│   ├── equity.bean
│   ├── expenses.bean
│   ├── income.bean
│   └── liabilities.bean
├── commodity
│   ├── __index.bean
│   └── fund.bean
├── doc
│   └── __index.bean
└── main.bean

4. 定期对账

账本的定期对账(或称定期断言,Balance Assertion)就像写代码时的「Ctrl + S」或「Command + S」,无事发生自动隐形,关键时刻出手「救命」。

断言就是告诉 Beancount,在某个日期前,这个账户有多少余额(设值为 A) 。如果 Beancount 计算的该时间点前的交易余额 B,与余额 A 不相等,那它就会报错。此时,我们只需检查两次断言日期之间的交易,就能快速定位错账。

使用 balance 命令标记某个日期前的账户余额(区分 bean-report 命令中的 balance 子命令),让 Beancount 自动核对账本中的账户余额是否与实际金额相等。

2023-01-01 balance Assets:Bank:Saving:ICBC 10,000.00 CNY

需要注意,断言声明的是所给日期开始前的余额,即当日的交易不算在内。也就是说,上面的断言表示,在 2023 年元旦前,即截止至 2022 年 12 月 31 日,工商银行储蓄账户余额为 10,000 元。

👉后记

在 wzyboy 的《Beancount——命令行复式簿记》一文中,我第一次了解到「记账神器 Beancount」;2022 年 9  月前后,我正式使用 Beancount 管理个人财务。如今睡前打开 VSCode 记录当天的资金变动,已经成为固定活动,而在每日的记账、查账中,我也获益良多。

本文分享的 Beancount 入门级操作指令,可以满足(个人)日常记账的简单需求;Beancount 还有许多证券投资、基金净值更新等高级应用,大家可以自行挖宝~

新的一年,坚持记账,搞钱发财!


编者语:# 编程之外 是 LigaAI 开设的全新栏目。在这里,我们将与开发者朋友们一起发现和分享生活中的「技术时刻」,并通过极具创意与实用的「生活代码」,感受「技术改善生活」的真谛。如果你也对「代码提升幸福感」感兴趣,欢迎关注 LigaAI 帐号

LigaAI 是新一代智能研发协作平台,我们关注研发协作与效率,重视开发者个人的价值创造。往期文章中,我们分享了许多敏捷开发、项目管理、个人成长与提升的文章,欢迎朋友们阅读交流。

体验新一代智能研发协作,请 点击这里 展开了解。LigaAI 助力开发者扬帆远航,期待与你一路同行!