用 Beancount 为团队记账
关于 Beancount 如何为团队记账的资料并不是很多,周末研究了两天,感觉有一点点收获,在这里做一下分享,如果对 Beancount 还不是很了解,可以先读一下入门系列文章:
团队目前的收入主要来源于苹果,而且收支账户用的是我个人的银行卡,我们就用这个现状来做例子,来讨论一下:如何通过使用 Beancount 在同一个账户下区分个人和团队的资产。团队在刚启动的时候没有启动资金来购买必需品,例如购买“苹果开发者凭证”,因此需要 beancount 能够正确记录出借资金,以及后续的归还操作。除此之外,还需要能够单独维护每个团队成员的账户,并且能够让团队成员随时查看自己的账户余额信息。下面用具体的例子来说明,满足这三个需求:
- 资产区分
- 借贷明晰
- 团队成员随时查看自己的账目
最后再讨论一下如何用 Beancount 给团队成员发股票。
托管账户与会计账户
开始之前先看一下账本的基本结构:
teamcount
├── accounting
│ ├── Alice
│ ├── Bob
│ ├── Carol
│ ├── David
│ ├── Edward
│ ├── ledger.bean
│ └── team
├── custody
│ ├── ledger.bean
│ ├── personal.bean
│ └── team.bean
├── ledger.bean
└── shares.bean
这里面借鉴了银行的记账方式,使用Cusody
和 Accounting
两个账户来记账。Custody
即托管账户,它的主要目的是保证账户数字是对的,银行账户本质上就是一个托管账户,它能保证你存 500,再取 300,余额一定是 200,但是它不负责记录为什么存 500 和为什么取 300,用 Beancount 的术语来说,就是 Custody
的记录只有 Income 和 Expenses两类。与托管账户相反,Accounting
即会计账户,不但要记录这 500 为什么来,还要记录是从哪里来的,记录在哪个资产下面。我们平时用 Beancount 做的记录其实都是会计账户。
可以用一个简单的方法来区分 Custody
和Accounting
:在记录一笔交易时,如果银行账户余额会随着交易完成而有所变动,则记录在 Custody
目录下。反之,如果交易不会导致银行余额变化,则记录在 Accounting
。
资产区分
Beancount 的使用始于开设帐号,好的账户设计是成功的一半,假设我个人的美国银行帐号有 $5000 美金,团队账户初始资金为 $0:
2024-01-01 * "Initial Account"
Assets:US:BofA:Joint:Personal 5000.00 USD
Assets:US:BofA:Joint:Team 0 USD
Equity:Opening-Balances
这里我使用了 Joint
关联帐号,而没有给 Team
单独开独立的虚拟账户主要有两个原因:一是因为这两个帐号的资金就是在同一个银行账户里,同时有能做到很好的区分。比如:当产品有收入从苹果转账进来时,可以直接入账团队账户,个人支出走个人账户:
2024-01-05 * "Income from Apple"
Income:Apple:ProductA -500 USD
Assets:US:BofA:Joint:Team 500 USD
2024-01-02 * "Netflex" "Purchase Subscription"
Assets:US:BofA:Joint:Personal -9.9 USD
Expenses:Netflex 9.9 USD
二是这样用 beancount 的 balance
校验时,可以用一行同时校验两个账户的总和,而这个总和恰好应该等于银行账户的余额:
2024-01-06 balance Assets:US:BofA 5490.1 USD
比较上下两种校验的写法,可以看到这里使用了 beancount “父结点等于所有子节点之和”这一特性:
2024-01-06 balance Assets:US:BofA:Joint:Personal 4990.1 USD
2024-01-06 balance Assets:US:BofA:Joint:Team 500 USD
通过这样的账户设置,就可以将同一个银行账户中,原来“不分你我”的资金,清晰的区分成个人和团队资金。下面我们再来看看如何从个人账户借款给团队账户。
借款与还款
初期阶段,团队资金为 0,团队花费的一些花费需要向我的个人账户借款购买,比如:域名,开发者证书等。等团队有了收入,再把这笔借款还上。以团队购买“苹果开发者许可”为例,来看一下一个完整的借贷过程是如何在 Beancount 中记录的。
首先在我个人账户里记录一笔应收帐款,表示借给了团队 99 刀:
2024-01-15 * "Team" "Lend Money to Team"
Assets:LA:Receivables:Profity 99 USD
Assets:US:BofA:Joint:Personal -99 USD
但是此时团队账户Assets:US:BofA:Joint:Team 账户里并没有钱,因此还要从团队账户的角度,记录一笔借款债务,并将借来的钱入库:
2024-01-15 * "Team" "Borrow Money From Personal"
Liabilities:Team:Payable:Personal -99 USD
Assets:US:BofA:Joint:Team 99 USD
然后就可以进行购买了:
2024-01-15 * "Apple" "Purchase Apple Developer License"
Assets:US:BofA:Joint:Team -99 USD
Expenses:Apple:License 99 USD
这样一笔记录分别记两笔看起来很麻烦,能不能直接从我的账户转钱给团队账户呢?Beancount 是允许这么操作的,但是缺点是,直接转账在账目看不到借款记录,将来可能就会忘记归还。而如果用了这样标准的出借流程,我个人的资产 Assets 里面有一笔应收帐款 99 USD,同时团队债务 Liabilities 里面也有一笔 -99 USD 的应付账款,就很清晰的标明有一笔借款未还。
还款的流程刚好相反,你也是需要做两笔记录:
- 团队账户偿还借款债务:
2024-01-06 * "Personal" "Pay Back Borrowed Money"
Assets:US:BofA:Joint:Team -99 USD
Liabilities:Team:Payable:Personal 99 USD
- 个人账户确认收款入账
2024-01-06 * "LA" "Received Lend Money"
Assets:Personal:Receivables:Team -99 USD
Assets:US:BofA:Joint:Personal 99 USD
为了更严格的Custody
里面的每一笔交易,最终的结果都能和银行余额对上,可以使用插件 “beancount.plugins.mark_unverified”,强制每一笔交易之后都必须有一个 balance 的检查,否则这条 txn 会被打上 unverified 的 metadata,这个metadata 信息在使用 fava 时,可以在 journal 视图中被标记出来。
团队成员如何查看自己账目
首先假设有团队账户有一笔收入,将这笔收入入账到团队账户:
2024-01-05 * "Income from Apple"
Income:Apple:ProductA -500 USD
Assets:US:BofA:Joint:Team 500 USD
这笔收入在归还购买开发许可的欠款之后,还剩 401 USD
2024-01-21 balance Assets:US:BofA:Joint:Team 401 USD
假设我们团队有 5 个人,每人分 80 USD,由于这个操作只是把资金分给团队成员的子账户上,并没有真的通过转账,打到团队成员的银行上,因此这个操作不会改变银行账户余额,所以这些记录放在 Accounting
这边。具体记录如下:
首先为每个团队成员在团队账户下创建一个子账户,然后从团队角度给员工发工资:
2024-01-25 * "Salary"
Assets:US:BofA:Joint:Team -400 USD
Expenses:Salary:Alice 80 USD
Expenses:Salary:BoB 80 USD
Expenses:Salary:Carol 80 USD
Expenses:Salary:David 80 USD
Expenses:Salary:Personal 80 USD ;myself in the team
然后再以员工角度使用 Income 收工资:
2024-01-25 * "Salary"
Assets:US:BofA:Joint:Team:Alice 80 USD
Income:Salary:Team -80 USD
这样记两笔虽然麻烦,但是的好处多多: 当这两本账目单独看的时候,都是完整的,符合 Beancount 记账规则的完整账目;而合起来看的时候,income 和 expenses 也都有相应的记录可以对账。
当员工需要把钱从虚拟账户里转到自己的账户里时,可以记录为 Expenses:
2024-01-30 * "Alice" "Transfer Money to her account"
Assets:US:BofA:Joint:Team:Alice -80 USD
Expenses:Salary:Alice
如何让团队成员随时查看呢,这时候就要用到 github 了,在 Github 上为每个员在组织账户里创建一个私有 repo,用来放 beancount 文件,例如:example-team/alice
,然后给该员工只读权限,最后也是最重要的一步,你把这个账户作为 submodule 克隆回到我们的总账目录下面。
这样员工可以随时查看他自己的账目,而我也可以在总账目下做完修改,通过提交 submodule 的修改,把账目同步出去即可。
发股票
在会计准则里,股票发行总量,会提现在 Equity 里面,以负数的形式来记录,比如说,我们 5 个人,股票均分,一个人 20%,Equity 应该减记股票 Share -100%。 由于 beancount 不支持百分比,因此就可以记录如下:
2024-01-01 * "Alice" "Team Share"
Assets:US:BofA:Joint:Team:Alice 20 SHARE
Equity:Team:Share
加一条记录,确认一下股票没有超发:
2024-01-30 balance Equity:Team:Share -100 SHARE
最后总结
Beancount 有很多灵活的特性,它不但可以为个人记账,还可以为团队记账。我们使用“资产类别:组件:组件:组件”的方式,来定义出不同的账户,包括个人账户,团队账户,以及团队成员账户,父结点等于所有子节点之和
这一特性非常好用。同时利用“每个文件都是一个单独账本入口”的特性,让这些账户都可以独立浏览。
当然,灵活性也是有代价了,在借贷过程中,需要重复记录两条数据,才能使每条记录”件件又着落“。我们还利用beancount 的纯文本文件,配合 github 为每个人开设了独立的账本空间,实现了简单的权限控制。最后还用到多币种的特性,为股票发放做了记录。
可以在 GitHub 上找到完整的例子源码: https://github.com/kidylee/teamcount