Beyond the Void
BYVoid
Beancount複式記賬(二):借貸記賬法

上一篇文章介紹了爲什麼要複式記賬,以及Beancount的基本特點。這篇言歸正轉,直接從實踐開始。

賬戶類別

複式記賬的最基本的特點就是以賬戶爲核心,Beancount的系統整體上就是圍繞賬戶來實現的。之前提到的會計恆等式中有資產、負債和權益三大部分,現在我們再增加兩個類別,分別是收入和支出。Beancount系統中預定義了五個分類:

  • Assets 資產
  • Liabilities 負債
  • Equity 權益(淨資產)
  • Expenses 支出
  • Income 收入

這五類是Beancount的約定,除此了Equity之下一些特殊的賬戶外,沒有任何預先定義的賬戶。用戶可以定義各種各樣的賬戶,Beancount對賬戶的組織是樹形的,譬如我分別有這些資產賬戶:

Assets:Cash:JPY
Assets:Cash:USD
Assets:Bank:CH:UBS
Assets:Bank:CN:BoC
Assets:Bank:US:Chase:Checking
Assets:Bank:US:Chase:Saving
Assets:Bank:JP:SMBC:JPY
Assets:Bank:JP:SMBC:USD
Assets:Broker:US:IB
Assets:Points:Airline:JAL
Assets:Points:Airline:United

Beancount對這些賬戶的組織形式如下圖:

賬戶

接下來是聲明賬戶的語法。Beancount要求每個使用的賬戶必須聲明開戶時間,格式是YYYY-mm-dd。之後是關鍵詞open,表示在這個日期開戶(或者開始記賬)。接下來是賬戶名稱,格式用:隔開的樹形語法,最後是(可以省略的)賬戶的貨幣種類。貨幣種類不需要事先定義,也沒有系統內部的定義,一般來說我們使用三字母的貨幣代碼,但其實可以用任何的名字(惟一的限制是大寫字母和下劃線)。我在這個例子中使用了USDJPYCNYCHF四個貨幣,以及我自定義的P_JALP_UA表示不同航空公司的里程。

2019-01-01 open Assets:Cash:JPY JPY
2019-01-01 open Assets:Cash:USD USD
2019-01-01 open Assets:Bank:CH:UBS CHF
2019-01-01 open Assets:Bank:CN:BoC CNY
2019-01-01 open Assets:Bank:US:Chase:Checking USD
2019-01-01 open Assets:Bank:US:Chase:Saving USD
2019-01-01 open Assets:Bank:JP:SMBC:JPY JPY
2019-01-01 open Assets:Bank:JP:SMBC:USD USD
2019-01-01 open Assets:Broker:US:IB USD, JPY, CHF
2019-01-01 open Assets:Points:Airline:JAL P_JAL
2019-01-01 open Assets:Points:Airline:United P_UA

賬戶如何組織分類完全看個人需求和喜好,譬如我先分賬戶類型,再分國家,然後是金融機構名,最後是具體賬戶。分類的作用是可視化的時候,可以看某個非字節點下面所有賬戶的彙總。

接下來是負債類別的賬戶,最常見的就是信用卡,組織方式和使用方法和資產賬戶沒有什麼區別,譬如:

2019-01-01 open Liabilities:CreditCard:US:Discover USD
2019-01-01 open Liabilities:CreditCard:JP:Rakuten JPY

在開始記賬之前,還差最後一步,就是收入和支出類別的定義。Beancount把收入支出的類別也想象成了一個賬戶,在語法上和資產、負債類賬戶沒有區別。譬如下面例子:

2019-01-01 open Expenses:Clothing
2019-01-01 open Expenses:Food:Dinner
2019-01-01 open Expenses:Transport:Airline
2019-01-01 open Expenses:Transport:Railway
2019-01-01 open Income:Salary
2019-01-01 open Income:Rebate

基本借貸記賬

有了以上定義的賬戶以後,我們終於可以開始實踐記賬了。複式記賬又叫作「借貸記賬」。之所以這麼叫,是因爲每一條記錄都至少有一條借記(Debit)和一條貸記(Credit)。可以看下面這個例子:

2019-01-01 * "日本航空" "紐約-東京"
  Expenses:Transport:Airline 1000 USD
  Liabilities:CreditCard:US:Discover -1000 USD

這個例子表示我在日本航空購買了紐約-東京的機票,消費1000美元(貸記),付款的信用卡Discover扣款1000美元(借記)。

Beancount基本的語法如下所示:

YYYY-mm-dd * ["payee"] "description"
  posting 1
  posting 2
  ...

第一行要有日期,接下來是*。收款者payee是可選的,如果*後面只有一個字符串,那就是省略了payee。從第二行開始,每一行開頭空兩個縮進,然後是賬戶名以及金額、貨幣。這裏有一個要點:要保證所有條目的總和是0,否則就會出現Transaction does not balance: (xxx USD)這樣的錯誤。這個要求很好理解,因爲花出去的錢必須和賬戶上減少的錢一樣,否則就是所謂的「賬目不平」了。

Beancount語法的靈活性在於每個記賬單元可以有任意多個條目(借記和貸記),只要保證它們的總和是0就可以。於是我們還可以這樣記錄:

2019-01-01 * "Walmart" "在超市買兩件衣服和晚餐"
  Expenses:Clothing 20 USD
  Expenses:Clothing 10 USD
  Expenses:Food:Dinner 10 USD
  Liabilities:CreditCard:US:Discover -40 USD

更加複雜的例子可能是這樣的:

2016-01-01 * "Google" "工資"
  Assets:Bank:US:Chase:Checking 500 USD
  Assets:Bank:US:Chase:Saving 1839.35 USD
  Assets:Pension:US:401k:PreTax 419.23 USD
  Assets:Pension:US:401k:PreTax 209.62 USD
  Expenses:Health:Insurance:Dental 3.14 USD
  Expenses:Finance:Insurance:TermLife 7.67 USD
  Expenses:Health:Insurance:Vision 0.98 USD
  Expenses:Tax:US:Federal 763.26 USD
  Expenses:Tax:US:Medicare 60.84 USD
  Expenses:Tax:US:SocialSecurity 260.15 USD
  Expenses:Tax:US:State:NY 212.59 USD
  Expenses:Tax:US:City:NYC 131.57 USD
  Expenses:Tax:US:State:NYDisability 1.2 USD
  Income:Salary:Regular -4192.31 USD
  Income:Allowance:TermLife -7.67 USD
  Income:Salary:401kMatch -209.62 USD

實際的記賬中,一進一出的兩個賬戶佔了絕大多數。這個時候把正負的金額寫兩遍未免有點羅嗦了,所以Beancount還提供了金額插值的功能。簡單說就是假設總和一定是0,在有N個賬戶的時候,只要求N-1個賬戶聲明金額。於是最初的例子還可以寫成:

2019-01-01 * "日本航空" "紐約-東京"
  Expenses:Transport:Airline 1000 USD
  Liabilities:CreditCard:US:Discover

在我的實踐中,我只在正好是兩個賬戶的時候纔使用這個功能,因爲可以避免重複的數字。但有多個賬戶的時候,把每個金額都寫出來有助於避免錯誤,和「防禦性編程」的理念一樣。

在上面的例子中,我們還可以看出來,所有Expenses類別的賬戶都是正數,所有Income類別的賬戶都是負數。這是Beancount及類似工具使用負數來表示借記(Debit),正數表示貸記(Credit)的結果。簡單來說,借記就是把賬戶上的資金移除,貸記就是增加賬戶的資金。同理,通常Assets類是正數,Liabilities類是負數。本質上每個賬戶的數值只有絕對值有意義,正負號並沒有實際含義。

貨幣轉換

如果在去國外旅遊,免不了要進行貨幣轉換。事實上Beancount本身沒有定義任何貨幣,這也意味着你可以定義任何貨幣(或商品)。所以哪怕不出國,只要是記錄了非主要貨幣類資產,譬如投資品,代金券,航空公司里程,那麼就需要貨幣轉換了。

在使用多個貨幣之前,需要先定義「工作貨幣」。工作貨幣可以不止一個,例如:

option "operating_currency" "JPY"
option "operating_currency" "USD"

定義了工作貨幣以後,在fava界面中可以看到工作貨幣單獨列出的欄目。

Beancount貨幣轉換的語法有兩種,一種是使用@記錄單位貨幣的轉換價格,例如:

2019-01-01 * "日本航空" "紐約-東京"
  Expenses:Transport:Airline 1000 USD @ 110 JPY
  Liabilities:CreditCard:JP:Rakuten -110000 JPY

另一種方式我更常用,使用@@記錄轉換後的總額:

2019-01-01 * "日本航空" "紐約-東京"
  Expenses:Transport:Airline 1000 USD @@ 110000 JPY
  Liabilities:CreditCard:JP:Rakuten -110000 JPY

貨幣轉換不一定只在一個賬戶上。下面的這個例子是以2.5日圓每點的價格,買了10000日本航空里程,但是付款的信用卡是以美元計價的,所以兩遍都可以轉換爲25000日圓來平衡。

2019-01-01 * "日本航空" "購買里程"
  Assets:Points:Airline:JAL 10000 P_JAL @ 2.5 JPY
  Liabilities:CreditCard:US:Discover -220.0 USD @@ 25000 JPY

借貸管理

複式記賬的強大之處是每個賬戶都有狀態,而且每個操作都是原子的,這對複雜的資金進出記錄非常有幫助。

生活中一個常見的例子是朋友之間的借錢和相互墊付,就拿我最近遇到一個例子來說吧,我和X、Y三人一起出遊,從東京附近的橫須賀坐船到猿島,費用是每人1300日圓的船票和200日圓的登島費,其中船票可以用信用卡支付,而登島費只能付現金。我們一共需要付4500日圓,但是正好誰都沒有這麼多現金,於是決定我用信用卡付三人的船票,X用現金付三人的登島費,最後再結算。

2019-05-25 * "猿島" "渡輪"
  Expenses:Transport:Ferry 1300 JPY ; 個人渡輪費用
  Assets:Receivables:X 1300 JPY ; 對X應收賬款
  Assets:Receivables:Y 1300 JPY ; 對Y應收賬款
  Liabilities:CreditCard:JP:Rakuten -3900 JPY

2019-05-25 * "猿島" "登島費"
  Expenses:Transport:Attraction 200 JPY ; 登島費
  Liabilities:Payable:X -200 JPY ; 欠X的錢

第二天,三人結算完畢,X付給我現金,Y轉賬給我。

2019-05-26 * "猿島" "費用結算"
  Assets:Receivables:X -1300 JPY ; X償還債務
  Liabilities:Payable:X 200 JPY  ; 償還對X的債務
  Assets:Cash:JPY 1100 JPY ; X實際付給我的錢到賬
  Assets:Receivables:Y -1300 JPY ; Y償還債務
  Assets:Bank:JP:SMBC:JPY 1300 JPY ; Y實際付給我的錢到賬

最終可以看出來,我在Expenses:Transport:Ferry類別消費1300 JPY,在Expenses:Transport:Attraction類別消費200 JPY,信用卡扣款3900 JPY,收到了1100 JPY的現金,Assets:Bank:JP:SMBC:JPY收到了1300 JPY的轉賬。

以上這種記賬方法可以讓資金的流動一目瞭然,類別和金額也準確無誤。記錄對他人的債權(應收賬款)和欠他人的債務(應付賬款),我分別使用了Assets:ReceivablesLiabilities:Payable下面的賬戶。

應收賬款和應付賬款的另一個用途是區分付款和到貨時間。一般來說交易是當場進行的,一個賬戶的借記和另一個賬戶的貸記同時發生,但是有些時候付款和到貨並不是同時發生的,如果需要精確區分發生的時間的話,可以用這種方法把他們分成兩筆記錄。

下面這個例子是,用信用卡買日本航空里程,但是不知道爲什麼過了1個月纔到賬:

2019-01-01 * "日本航空" "購買里程"
  Assets:Receivables:JAL 10000 P_JAL @@ 25000 JPY
  Liabilities:CreditCard:US:Discover -220.0 USD @@ 25000 JPY

2019-02-01 * "日本航空" "里程到賬"
  Assets:Points:Airline:JAL 10000 P_JAL
  Assets:Receivables:JAL

這篇文章到此爲止,Beancount最基本的用法已經介紹完畢了。用這些簡單的語法,我們已經可以滿足大部分的記賬需求了,但Beancount的強大之處遠遠不止於此。

下一篇我會繼續介紹Beancount的更多用法,包括如何高效對賬和資產折舊。同時歡迎加入Beancount中文討論:t.me/beancount_zh


上次修改時間 2019-05-27

相關日誌