Beancount使用拾遗

Knowledge comes, but wisdom lingers. It may not be difficult to store up in the mind a vast quantity of facts within a comparatively short time, but the ability to form judgments requires the severe discipline of hard work and the tempering heat of experience and maturity.
Calvin Coolidge

背景

因为近期可能要处理一些会计工作,就了解了一下简单的会计知识。发现了一个用于复式记账的软件:Beancount。这个软件比较适合程序员群体用来作为个人的会计软件。我虽然不是程序员,但是因为比较喜欢命令行、纯文本、自动化、自主可控、隐私安全等方面,所以也对这种记账工具产生了兴趣,决定试验一下。

Beancount简介

Beancount的简介可以参考[1]、参考[2]文章的内容。我的理解是一套复式记账的方法以及配套的一系列自动化和展示工具。

Beancount的核心是一套用纯文本,按照Beancount设定的规则进行记账的方法。好处是不依赖任何平台和软件,没有隐私泄露的问题和平台绑定的问题,可以使用程序员源代码管理的那一套工具(git)来进行账本的管理。缺点是有点门槛,使用起来可能没有一些记账app那么方便。

不过有价值的工作总是有门槛的,复式记账法有助于培养一个人的会计思维,对自己的财务有更深刻的认识,还是值得的。

一些拾遗

关于Beancount的使用方法,文末参考部分给出的内容非常详细了,不再赘述。

不过我在导入微信账单的时候,使用参考[6]参考[8]提供的代码都有问题,研究了很久,也没有找到答案,并且网上也没有梳理import流程的文章,导致定位问题也有点困难。可能对程序员很简单,但是对非程序员来说有点难度。我经过反复思考和测试,有一点收获,在这里分享一下。

问题

使用参考[6] 或参考[8] 提供的代码,根据指示,用bean-extract命令:bean-extract config.py XXXX.csv test.bean, 来从微信账单生成bean交易账本文件,执行成功,但是生成的test.bean文件只有28个字节,内容是空的,没有实质内容。

定位

bean-extract是个exe文件,不知道如何调试,着急了很久,后来想到config.py 和CSVImporter.py 文件都是标准的python代码,可以在其中加print来调试,通过一步步的调试,发现了通过bean工具进行账单import的流程。

Beancount导入账单的流程

bean-extract命令其实只是一个入口,和关于bean文件处理的库函数。对输入文件(原始账单文件)的解析来自类Importer。config文件中定义了两个importer:

1
CONFIG = [wechat_importer, alipay_importer]

通过print调试发现,无论是使用bean-identify,还是bean-extract命令,都会调用config.py文件,让后生成config.py文件中CONFIG 列表中引用的这两个importer对象。然后都会调用 identify函数,这个函数会判断文件的类型是否是text/csv,以及文件的前缀是否是对象配置中的前缀。

所以导入的问题,就在于win下下载的微信支付清单是application/vnd.ms-excel 类型,而不是代码中要求的text/csv类型,所以直接退出了。而生成的支付宝对象,在这里检测到前缀与实际文件不同,也退出了。

总结一下bean-extract(identify)的流程:首先根据config.py文件中的CONFIG数组来生成importer对象,对象的参数在config.py文件中,对象的实现在CSVImporter.py中。相关对象生成后,通过Idengtify函数检查文件是否满足本对象的要求(文件类型和文件名前缀),再调用extract函数生成交易文件。

解决方案

定位到了问题,解决方案就很简单。修改Importer类中判断文件类型的代码,通过"application/vnd.ms-excel"类型的文件。

1
2
3
4
#if file.mimetype() != "text/csv":
if file.mimetype() not in ["text/csv", "application/vnd.ms-excel"]:
print("Wrong file type")
return False

其他

本次问题的定位和处理,是在ChatGPT的帮助下完成的。因为作者在编写python代码时,用了不少高级的属性,我仅有的一点python编程知识无法理解,但是将代码丢给ChatGPT后,基本可以得到很清晰的解释,在此表示感谢。

参考

[1] 记账神器beancount - 拾月 入门文章,介绍的很详细,给出了账户、拆分账本及账本结构的示例,基本够用了
[2] Beancount复式记账(一):为什么 系列文章,值得参考
[3] Shanhe Yi - 复式借贷记账法 Beancount 系列文章,值得参考,包括了房产、RSU和ESPP的建模方法
[4] Beancount 最佳实践 — XWARTZ 入门文章,参考
[5] 开始使用 Beancount | Stdio’s Blog 提到了telegrambot,后续可以参考
[6] 用于支付宝和微信账单的Beancount Importer - 知乎 导入支付宝和微信账单的教程,作者提供了代码,见[7]
[7] GitHub - sphish/Beancount-CSVImporter: CSVImporter for beancount, mainly used to import transaction records of Alipay and WeChat 参考[6]作者提供的importer的源码,几乎直接可用
[8] 使用 Beancount 记账篇二:各类账单导入 | Verne in GitHub 另外一个作者写的importer,包括了银行的、支付宝和微信的,可以参考