使用 Beancount 进行基金会计
Martin Blais, Carl Hauser, 2014 年 8 月
http://furius.ca/beancount/doc/proposal-funds
关于如何在 Beancount 中实现基金会计的讨论,涵盖各种方法、解决方案及可能的扩展。
动机
许多用户正在尝试使用命令行会计系统解决基金会计问题,部分原因是这类会计常出现在预算有限的非营利组织中,它们更倾向于使用免费软件;另一部分原因是这类场景所需的灵活性和定制化特性与命令行记账系统高度契合。
什么是基金会计?
例如,参见此讨论帖:
“我计算的另一项宗教义务实际上是什一奉献(我们称之为 Huqúqu'lláh,其计算方式不同,但那是另一个话题)。为了计算应缴的什一税,我会将每笔存款的 19% 累计到一个虚拟账户中,然后从该账户中扣除每笔必要支出的 19%。
年末剩余的总额即为我应缴纳的什一税。这个什一税账户并非真实账户,因为它不存在于任何金融机构中;但它作为个人义务却非常真实。通过使用虚拟账户,我可以追踪这种‘旁路’负债,并在时机成熟时从资产账户中支付。如果我使用 --real 报告,我将仅看到已支付给该负债的金额;而如果不使用 --real,我则能看到当前欠付的 Huqúqu'lláh 总额。”
—— John Wiegley
以下是另一位用户的评论描述:
[...] 基本上,其理念是将你的财务生活划分为多个称为“基金”的独立资金池。每个基金都有其自身的会计科目表(在一定程度上),且每个基金都遵循“资产 + 负债 + 净值 = 0”的平衡原则。这在非营利组织中尤为必要,因为用于特定目的的资金必须单独核算。唯一无法完全分离的领域是实际的资产账户(如银行账户)和实际的负债账户(如信用卡)可能同时为多个基金持有或承担债务,因此无法使用完全独立的账本文件。在我们的教会中,我们使用名为 PowerChurchPlus 的程序,效果非常好。我妻子现在担任一个社区音乐组织的司库,正面临同样的问题,但由于规模极小,购买商业软件的成本并不合理。
我看过在 ledger-cli 邮件列表中关于使用 C++ ledger 进行非营利组织会计的讨论,但感觉要正确且一致地使用标签需要极高的自律性。而‘基金’的概念则更容易解释和使用(并且自然地强制执行了余额账户的不变性)。因此,我查看了 Beancount 的代码,想看看是否能将其改造以支持基金会计。我认为答案是‘可以,并且相对容易实现’。此外,我认为这个想法对个人也有用处:有几个场景显而易见。首先,我居住在一个共同财产州。我和妻子各自可能继承属于我们个人的财产,同时我们也有共同财产。这些可以分别视为独立的基金,我们既能单独报告它们,也能合并起来以全面了解我们的财务状况。同样,为每个人设立单独的退休金基金也可能很有意义。
—— 卡尔·豪舍
摘自 PowerChurchPlus 11.5 手册(PowerChurch, Inc. 2013):
“在会计中,‘基金’一词具有非常特定的含义。会计基金是一个自平衡的会计科目表。[…] 在会计中,我们需要将基金视为教会的一个部门或子组。每个会计基金都拥有自己独立的资产、负债、权益、收入、转账和费用账户。
那么,何时应使用额外的基金?如果你的教会中某个部门需要独立生成财务报告,你就需要设立额外的基金。例如,如果你的教会运营一所幼儿园或学前班,你可能希望设立一个独立基金,将其财务与教会整体财务分开管理。根据你的需求,你甚至可以为男性或女性团体分别设立独立基金。你甚至可以设立一个新基金,专门追踪所有固定资产,与日常运营账户分开管理。"
这是一个有趣且相当普遍的问题。本节其余部分将描述相关使用场景。
联合账户管理
我曾亲自使用这种‘基金会计’方法来管理我和前妻的联合账户:我们各自拥有个人账户——都是职业人士——并根据需要向联合账户注资。本节将描述我是如何实现这一做法的1。
联合账户的会计记录保存在一个独立文件中。我们创建了两个子账户,分别记录我们各自的‘份额’:
2010-01-01 open Assets:BofA:Joint
2010-01-01 open Assets:BofA:Joint:Martin
2010-01-01 open Assets:BofA:Joint:Judie
转入联合账户的资金直接记入这两个子账户之一:
2012-09-07 * "Online Xfer Transfer from CK 345"
Assets:BofA:Joint:Judie 1000.00 USD
Income:Contributions:Judie
当我们产生支出时,我们会通过两条分录减少资产账户,每条对应一个子账户。我们通常按 2:1 的比例记账,以反映收入差异,或者我经常将大部分交易记在自己名下(精确记账并不意味着我们彼此不够慷慨):
2013-04-27 * "Urban Vets for Grumpy"
Expenses:Medical:Cat 100.00 USD
Assets:BofA:Joint:Martin -50 USD
Assets:BofA:Joint:Judie -50 USD
2013-05-30 * "Takahachi" "Dinner"
Expenses:Food:Restaurant 65.80 USD
Assets:BofA:Joint:Judie -25.00 USD
Assets:BofA:Joint:Martin
由于我们对此并不十分精确,因此省略其中一个金额非常方便。
处理多个基金
(由卡尔·豪舍提供)
以下是上述 PowerChurchPlus 系统所采用的模型(将其中使用的账户编号替换为 Beancount 风格的名称)。“基金”名称位于账户名称的前面。
Operations:Assets:Bank:...
Endowment:Assets:Bank:...
Operations:Liabilities:CreditCard:...
Endowment:Liabilities:CreditCard:...
Operations:Income:Pledges:2014
Operations:Expenses:Salaries:...
Operations:Expenses:BuildingImprovement:...
Endowment:Income:Investments:...
Endowment:Expenses:BuildingImprovement:...
…
任何交易都必须在所涉及的每个基金内保持平衡。例如,我们的捐赠基金经常资助超出当前捐赠收入能力的开支。
2014-07-25 * "Bill’s Audio" "Sound system upgrade"
Endowment:Assets:Bank1:Checking 800.00 USD
Operations:Assets:Bank1:Checking 200.00 USD
Endowment:Expenses:BuildingImprovement:Sound -800.00 USD
Operations:Expenses:BuildingImprovement:Sound -200.00 USD
这表示一笔从捐赠基金和运营基金的资产中支付给比尔的音频费用的单一检查,这两个基金的资产均存放在单一的外部资产账户 Assets:Bank1:Checking 中。
注释 1:允许基金名称为空,并省略后续的“:”,事实上,对于不想使用这些功能的用户,这可以作为默认设置。(即,如果你不使用这些功能,一切保持不变。)名称为空字符串的基金显然与其他所有基金不同。
注释 2:对于参与多个基金的账户,balance 和 pad 指令作用有限。使用它们需要知道该账户在不同基金之间的分配比例,而外部持有方(如银行)提供的账户对账单通常不包含此类信息。或许可以允许类似以下内容作为校验手段,
2014-07-31 balance *:Assets:Bank1:Checking 579.39 USD
但通过 pad 条目自动修正似乎是不可能的。
可以针对任何基金或任意组合的基金生成资产负债表报告,且报告将保持平衡。您可以轻松追踪每种用途所对应的资产情况。基金间的转账将记录为:一方基金的支出和资产减少,另一方基金的收入和资产增加。用于转账的收入和支出账户可以是通用的(如 Operations:Income:Transfer),也可以是为特定类型收入或支出设立的账户(如 Endowment:Expense:BuildingImprovement:Sound)作为转账交易的一方,都是完全可行的。
此处的账户命名语法仅是一种可能的实现方式,它依赖于 Beancount 使用的五个特定命名的顶层账户。第一个此类账户左侧的所有部分可视为基金名称,或者也可使用其他分隔符来区分基金部分与账户名称部分。同样,我仅展示了单层基金名称,但基金名称也可以是层级结构的。我不确定这种层级结构的价值,但请注意:如果交易在叶子级基金层面保持平衡,那么在更高层级的基金中也会保持平衡,这或许具有一定的实用意义。
针对 John W. 的 Huqúqu'lláh 示例,可以设置一个基金,其负债为“道德义务”而非法律义务(这似乎是反对将什一税直接记录在普通负债账户中的原因)。当收入到账时(例如,直接存入实际银行支票账户),将其中的 19%记入“道德义务”基金的支票账户,并同时记录相应的负债。当需要支付相关费用时,从“道德义务”基金的支票账户中转回 19%,并减少对应的负债。无需使用虚拟记账或交易——所有交易必须保持平衡。如果例如我们设有 HisRetirement 基金和 HerRetirement 基金(出于遗产规划目的,分开记录很有用),但更常见的是我们希望了解合并后的退休金情况,此时可定义一个虚拟基金 OurRetirement,其值等于 HisRetirement 和 HerRetirement 的总和。请注意,这仅在生成报告时才重要:在每个真实基金中,只需进行正常的复式记账并保持交易平衡即可。当我提到两个基金的“总和”时,意思是:先去除基金名称,取其包含账户名称的并集,然后对共同账户的余额求和,并保留其他账户的余额。
(资产负债表) 在报告时,我们希望具备按基金进行余额统计以及对一组基金的余额进行汇总的能力。我还使用一种报表,其中每个基金占一列,对应的账户名称水平对齐,并在右侧设置一列作为“合计”。当该报表包含所有基金时,就能全面展现你所拥有和欠下的资产,以及不同用途或受不同限制的资金情况。以下是教会部分基金的资产负债表示例。术语略有不同:Beancount 中的“权益”在这里称为“净资产”。由于在 PowerChurchPlus 中使用大量基金并不方便,因此净资产实际上按不同用途进行了分类——我认为我们在此探讨的理念在此处能真正大放异彩:如果基金创建和组合报告变得极其简便,那么 PCP 中用于在基金内部划分资产的某些机制就变得多余了。
(损益表) 对于收入与支出报表,我通常只关注单个基金的支出,但如果需要,将两个基金合并计算也完全合理。
对我而言,这种基金会计方法具有吸引力,因为它依赖并保留了复式记账法的基本原则:当交易总和为零时,资产负债表等式始终成立。由此我们自动获得了组合任意一组基金的能力(在录入交易或组织账户深层结构时无需做任何特殊处理),且至少在算术上是合理的;我们也不依赖任何与重命名或标记相关的“魔法”。我不认为将“基金”概念下推到账户层级中能如此简单或清晰地实现:基金应位于五个根账户(资产、负债、权益、收入和支出)之上,而非之下。
实现思路
目前是一些随机的想法,还需要进一步完善。
-
如果需要多重冗余分录,可以通过使用插件自动生成。例如,若采用类似镜像记账的技术来“将同一笔资金分配至多个账户”,至少用户无需手动操作,否则既繁琐又容易出错。
-
可在解析时使用重命名账户的流程,以便将多个文件合并为一个。(允许用户安装此类映射规则是我长期考虑但尚未实现的想法,不过可通过插件过滤器实现。)
-
我们可以利用子账户的交易可合并并汇总至父账户这一特性(尽管目前报表功能在这一方面尚有滞后,但最终会实现)。
-
在之前关于对资金(Funds)采用类似标签栈方法的讨论基础上,如果我们将当前的标签架构扩展,允许标签携带值,例如
#fund=Operations,或#fund=Endowment,称之为“值标签”。同时,还需要允许记账条目(postings)拥有标签。值标签的语义如下:每个记账条目中,同一键的值标签只能出现一次;显式附加在记账条目上的标签会覆盖从交易继承的值标签;显式附加在交易上的标签会覆盖标签栈中的值;且仅应用标签栈中最后一个具有相同键的值标签。这使得资金(Funds)的优先级略低于先前提出的将资金置于账户名前的方案,但规避了之前提到的轻微解析难题。该方案暗示无需在资金内开设账户,而之前的语法则暗示需要这样做。每个交易中资金的严格平衡规则仍可通过插件实现。而针对某个资金(或多个资金)的报表生成方式如下:-
选择包含与目标资金(或资金)匹配的任何记账条目的交易
-
收集(必要时按常规方式求和)与所报告资金(或资金)相关的记账条目(A)
-
收集(按常规方式求和)所选交易中与目标资金无关的记账条目(B)
-
生成报表,将(A)作为目标资金(或资金)的信息,(B)作为“其他”。设置“其他”是为了确保报表平衡,但可根据需要选择省略。
-
From an implementation perspective this seems more orthogonal to the current status quo, requiring even less change to existing code. It adds a new feature -- value tags and that can then be used by plugins and new reports to do what we want for fund accounting.
示例
(Carl) 以下是我如何处理与工资相关的事项的示例,其中涉及递延补偿(403(b)——与 401(k)极为相似)和灵活支出账户(与之前在 ledger-cli 群组中讨论过的 HSA 类似)。
不使用资金
(Carl) 首先,不使用资金(此方案可通过 bean-check 验证):
这是在没有资金功能的情况下,我设置工资单、健康保险、FSA 和 403b 供款的方式。一个问题在于,它直接将总收入分配到 403b 和 FSA 账户,尽管它已认识到健康保险供款是工资的减少,而 403b 和 FSA 也应被视为工资减少。因此,追踪这两项供款以及应税收入变得更加困难。
通过深入思考,我们可以解决这个问题——我们会创建收入和支出类账户来代表这些供款,但在我看来,这些账户看起来会相当奇怪,因为它们完全属于账户系统内部的构造。
请参阅下一个示例,了解使用资金时的效果。如果你伸出舌头、揉肚子并倒立,你会发现基于资金的解决方案在交易复杂性上与上述方案完全等价——所需行数相同。主要优势在于心理层面——它能更清晰地帮助你理解如何保持一致性和实用性。
option “title” “Paystub - no funds”
2014-07-15 open Assets:Bank:Checking
2014-07-15 open Assets:CreditUnion:Saving
2014-07-15 open Assets:FedIncTaxDeposits
2014-07-15 open Assets:Deferred:R-403b
2014-07-15 open Expenses:OASI
2014-07-15 open Expenses:Medicare
2014-07-15 open Expenses:MedicalAid
2014-07-15 open Expenses:SalReduction:HealthInsurance
2014-07-15 open Income:Gross:Emp1
2014-07-15 open Income:EmplContrib:Emp1:Retirement
2014-01-01 open Assets:FSA
; This way of setting up an FSA looks pretty good. It recognizes the
; rule that the designated amount for the year is immediately available
; (in the Asset account), and that we are obliged to make contributions
; to fund it over the course of the year (the Liability account).
2014-01-01 open Liabilities:FSA
2014-01-01 ! "Set up FSA for 2014"
Assets:FSA 2000 USD
Liabilities:FSA -2000 USD
2014-07-15 ! "Emp1 Paystub"
Income:Gross:Emp1 -6000 USD
Assets:Bank:Checking 3000 USD
Assets:CreditUnion:Saving 1000 USD
Assets:FedIncTaxDeposits 750 USD
Expenses:OASI 375 USD
Expenses:Medicare 100 USD
Expenses:MedicalAid 10 USD
Assets:Deferred:R-403b 600 USD
Liabilities:FSA 75 USD
Expenses:SalReduction:HealthInsurance 90 USD
Income:EmplContrib:Emp1:Retirement -600 USD
Assets:Deferred:R-403b
2014-01-01 open Expenses:Medical
2014-07-20 ! "Direct expense from FSA"
Expenses:Medical 25 USD
Assets:FSA
2014-07-20 ! "Medical expense from checking"
Expenses:Medical 25 USD
Assets:Bank:Checking
2014-07-20 ! "Medical expense reimbursed from FSA"
Assets:Bank:Checking 25 USD
Assets:FSA
使用资金
(Carl) 现在使用资金(使用提议的功能,因此无法通过 bean-check 验证):
这是使用资金功能时,我设置工资单、健康保险、FSA 和 403b 供款的方式。我可以直接安排,使 FSA 和 403b 的供款被明确视为收入税意义上的工资减少。同时,我可以轻松查看自己和雇主各自向 403b 账户的供款金额。
参见前面的示例,了解不使用资金账户时的情况,但那样不够准确。
这并不能追踪 403b 资金最终应缴纳的税款。我认为这取决于个人选择采用现金制还是权责发生制会计。如果是现金制,这些税款不属于当期负债,不能作为负债报告;如果是权责发生制,则在确认收入时,这些税款应作为当期负债记录。
对于现金制账簿,我们希望具备报告税款应缴状态的能力,但这属于报告层面的问题,而非记账层面。我们需要确保有足够的可识别信息,以便自动化生成这些报告。我认为采用基于资金的会计视角可以轻松实现这一点。
尚未解决的问题:如果联邦和州的计税基础不同,或联邦与多个不同州的计税基础均不同时,该怎么办?天哪!
我采用的惯例是资金名称位于根账户名称之前。注意,通过适当的逆向思维和数据透视规则,你也可以将资金名称放在其他位置。将其放在首位,可以强调它标识了一组必须保持平衡的账户,并使交易处理器更容易确保这一属性。没有前置资金名称的账户属于名称为空字符串的资金。
option "title" "Paystub - no Funds"
2014-07-15 open Assets:Bank:Checking
2014-07-15 open Assets:CreditUnion:Saving
2014-07-15 open Assets:FedIncTaxDeposits
2014-07-15 open Expenses:OASI
2014-07-15 open Expenses:Medicare
2014-07-15 open Expenses:MedicalAid
2014-07-15 open Expenses:SalReduction:HealthInsurance
2014-07-15 open Expenses:SalReduction:FSA
2014-07-15 open Expenses:SalReduction:R-403b
2014-07-15 open Income:Gross:Emp1
2014-07-15 open Income:EmplContrib:Emp1:Retirement
2014-01-01 open FSA:Assets ; FSA fund accounts
2014-01-01 open FSA:Income:Contributions
2014-01-01 open FSA:Expenses:Medical
2014-01-01 open FSA:Expenses:ReimburseMedical
2014-01-01 open FSA:Liabilities
2014-07-15 open Retirement403b:Assets:CREF ; Retirement fund accounts
2014-07-15 open Retirement403b:Income:EmployeeContrib
2014-07-15 open Retirement403b:Income:EmployerContrib
2014-07-15 open Retirement403b:Income:EarningsGainsAndLosses
; This implements the same idea as above for the FSA, of balancing
; Assets and Liabilities at the opening, but now does it using a
; separate Fund.
2014-01-01 ! "Set up FSA for 2014"
FSA:Assets 2000 USD
FSA:Liabilities -2000 USD
2014-07-15 ! "Emp1 Paystub"
Income:Gross:Emp1 -6000 USD
Assets:Bank:Checking 3000 USD
Assets:CreditUnion:Saving 1000 USD
Assets:FedIncTaxDeposits 750 USD
Expenses:OASI 375 USD
Expenses:Medicare 100 USD
Expenses:MedicalAid 10 USD
Expenses:SalReduction:R-403b 600 USD
Retirement403b:Income:EmployeeContrib -600 USD
Retirement403b:Assets:CREF 600 USD
Expenses:SalReduction:FSA 75 USD
FSA:Income:Contributions -75 USD
FSA:Liabilities
Expenses:SalReduction:HealthInsurance
Retirement403b:Income:EmployerContrib -600 USD
Retirement403b:Assets:CREF
2014-01-01 open Expenses:Medical
2014-07-20 ! "Direct expense from FSA"
FSA:Expenses:Medical 25 USD
FSA:Assets
2014-07-20 ! "Medical expense from checking"
Expenses:Medical 25 USD
Assets:Bank:Checking
2014-07-20 ! "Medical expense reimbursed from FSA"
Assets:Bank:Checking 25 USD
Income:ReimburseMedical
FSA:Assets -25 USD
FSA:Expenses:ReimburseMedical
转账账户提案
作者:Carl Hauser
我在使用资金方法时遇到的一个问题是,在资金之间转账时(例如上面最后一笔交易)很容易出错。正式引入“转账账户”的概念有助于解决这一问题。最常见的错误是导致两个账户的资产变动方向相同——都增加或都减少,如下所示的错误交易版本:
2014-07-20 ! "Medical expense reimbursed from FSA - with mistake"
Assets:Bank:Checking 25 USD
Income:ReimburseMedical
FSA:Assets 25 USD
FSA:Expenses:ReimburseMedical
这笔交易虽然平衡了,但并非我们想要的结果。假设我们引入转账账户的概念。它们在层级结构中的位置与收入和支出账户相同,也属于非资产负债表账户。但它们仅在涉及多个资金的交易中发挥作用。对于包含转账账户的交易,还有一条额外规则:转账总额也必须为零(此规则在原有“每个资金内部交易必须平衡”的规则基础上增加)。因此,我们需要这样设置:
2014-07-15 open FSA:Transfer:Incoming:Contribution
2014-07-15 open FSA:Transfer:Outgoing:ReimburseMedical
2014-07-15 open Transfer:Outgoing:FSAContribution
2014-07-15 open Transfer:Incoming:ReimburseMedical
由于转账总额为-50 USD而非零,上述错误交易现在会被标记出来。
2014-07-20 ! "Medical expense reimbursed from FSA - with mistake"
Assets:Bank:Checking 25 USD
Transfer:Incoming:ReimburseMedical
FSA:Assets 25 USD
FSA:Transfer:Outgoing:ReimburseMedical
使用转账账户处理 FSA 和退休账户的工资单交易可能如下所示(当然需先执行适当的open操作):
2014-07-15 ! "Emp1 Paystub - using transfer accounts"
Income:Gross:Emp1 -6000 USD
Assets:Bank:Checking 3000 USD
Assets:CreditUnion:Saving 1000 USD
Assets:FedIncTaxDeposits 750 USD
Expenses:OASI 375 USD
Expenses:Medicare 100 USD
Expenses:MedicalAid 10 USD
Transfer:Outgoing:Retirement403b:SalReduction 600 USD
Retirement403b:Transfer:Incoming:EmployeeContrib
Retirement403b:Assets:CREF 600 USD
Transfer:Outgoing:FSA:SalReduction 75 USD
FSA:Transfer:Incoming:Contributions
FSA:Liabilities
Expenses:SalReduction:HealthInsurance
Retirement403b:Income:EmployerContrib -600 USD
Retirement403b:Assets:CREF
有些人可能认为这过于复杂。在不改变转账账户概念或规则的前提下,你可以简化记账,仅对每个资金使用一个账户Fund:Transfer,虽然会损失部分报告的精确性,但依然能确保转账交易的正确性。
账户别名
Simon Michael 提到,这与 HLedger 的账户别名相关:
“我认为这与你希望分别和合并查看实体财务状况的情形有关。账户别名是实现这一目标的另一种方式,详见http://hledger.org/how-to-use-account-aliases。”
-
如果你发现自己在现代生活方式面前感到文化上的不适,或许你可以想象一下合租室友的情况,尽管我不喜欢这种联想带来的简化视角。↩