前払い費用を資産として記録し、毎月の負担分を通常のBeancount取引で費用に振り替えます。以下のスクリプトは、保険、ソフトウェア、リテイナー(顧問料)、設備の減価償却について、完全で再現可能な元帳を出力します。Python 3が必要で、サードパーティ製ライブラリは不要です。
例えば、6ヶ月分の自動車保険料が一括で600ドルかかる場合、毎月100ドルずつ6回に分けて振り替えることで、現金支払いと費用計上を分離し、効果的な予算編成に役立ちます。
償却とは何か?
償却とは、無形資産または前払い項目のコストを、その便益が及ぶ期間にわたって分散させることです。以下の例では、経営レポート用にシンプルな月次基準を使用しています。これらは税務上の控除や法定の減価償却方法を決定するものではありません。
Beancountでの解決策:fava.plugins.amortize_over
互換性確認日 2026-09-07: fava.plugins.amortize_over は、標準のFava 1.30.16のプラグインディレクトリには存在しません。その標準インストールに plugin ディレクティブを追加すると、インポートエラーが発生します。ここで紹介する移植可能な例は、Beancount 3.2.3、beanquery 0.2.0、Fava 1.30.16でテストされています。
Beancount.ioのカスタムソースには amortize_over の実装が含まれています。これは、厳密に2つの転記と amortize_months メタデータを持つ、別々の支払い取引とスケジュール取引を期待します。その月次日付はスケジュールの元の日に従い、読み込み時に将来のコピーを省略します。その丸めルールは、残りの期間にわたってセントを分配します。このソースの証拠は、ホストされたデプロイが現在どのバージョンを実行しているかを確定するものではありません。以下に示す明示的なスケジュールには、独自の記載日付と最終期間の丸めルールがあります。
ステップ1:プラグインを有効にする
このワークフローで有効にするプラグインはありません。 ステップ3のPythonブロックを amortize.py として保存します。uv をインストールして、ここで使用したバージョンで検証およびクエリコマンドを実行します。Favaはウェブレポートが必要な場合にのみ必要です。
スクリプトは通常の取引を標準出力に書き出します。その出力を新しいサンプルファイルにリダイレクトし、内容を確認してから、エントリを帳簿に組み込む前に検証してください。> で再実行すると生成されたサンプルファイルが置き換わります。>> で追記すると取引が重複します。
ステップ2:勘定科目を構造化する
生成される各ファイルは、スタンドアロンのサンプル元帳です。保険の例では、保険料支払い前に以下の勘定科目を開設し、説明用の600ドルの期首銀行残高を設定します。
| 勘定科目 | 目的 |
|---|---|
Assets:Bank:Checking | 支払いに使用する現金 |
Assets:Prepaid:Insurance | 費用計上待ちの保険料 |
Expenses:Insurance:Auto | 毎月の保険料 |
Equity:Opening-Balances | サンプルの初期現金の相手勘定 |
生成された取引を既存の元帳に適用する場合は、実際の勘定科目の開設と銀行残高を使用してください。すでに資金がある口座にサンプルの初期現金を追加したり、すでに帳簿に記録されている購入を再度記録したりしないでください。
ステップ3:償却取引を記録する
この完全なプログラムを amortize.py として保存します。各シナリオは、支払日、月次リリース回数、購入資産、費用勘定、およびリリースによって貸方記帳される勘定科目を指定します。最初のリリースは支払日です。以降のリリースは翌月以降の同じ日に発生し、必要に応じて月末にクランプされます。
import argparse
import calendar
from datetime import date
from decimal import Decimal, ROUND_HALF_EVEN
# amount, months, payment date, purchase asset, expense, release credit account
SCENARIOS = {
"insurance": (
"600.00", 6, "2024-06-01", "Assets:Prepaid:Insurance",
"Expenses:Insurance:Auto", "Assets:Prepaid:Insurance",
),
"software": (
"1200.00", 12, "2024-01-15", "Assets:Prepaid:Software",
"Expenses:Software:Adobe", "Assets:Prepaid:Software",
),
"retainer": (
"4500.00", 3, "2024-01-05", "Assets:Prepaid:Professional",
"Expenses:Professional:Legal", "Assets:Prepaid:Professional",
),
"equipment": (
"3000.00", 36, "2024-01-20", "Assets:Equipment:Computers:Cost",
"Expenses:Depreciation:Computers", "Assets:Equipment:Computers:AccumDep",
),
}
parser = argparse.ArgumentParser()
parser.add_argument("scenario", choices=SCENARIOS)
args = parser.parse_args()
amount, months, paid, asset, expense, credit = SCENARIOS[args.scenario]
total = Decimal(amount)
start = date.fromisoformat(paid)
monthly = (total / months).quantize(Decimal("0.01"), rounding=ROUND_HALF_EVEN)
bank = "Assets:Bank:Checking"
equity = "Equity:Opening-Balances"
def transaction(day, narration, debit, credit_account, value):
print(f'\n{day} * "{narration}"')
print(f" {debit} {value:.2f} USD")
print(f" {credit_account} {-value:.2f} USD")
print('option "operating_currency" "USD"')
for account in sorted({bank, equity, asset, expense, credit}):
print(f"2024-01-01 open {account} USD")
transaction("2024-01-01", "Example opening cash", bank, equity, total)
transaction(paid, f"Pay {args.scenario}", asset, bank, total)
for index in range(months):
year, month_index = divmod(start.year * 12 + start.month - 1 + index, 12)
month = month_index + 1
day = min(start.day, calendar.monthrange(year, month)[1])
release_date = date(year, month, day)
# Put the entire rounding remainder into the final release exactly once.
release = monthly if index < months - 1 else total - monthly * (months - 1)
transaction(release_date, f"{args.scenario} release {index + 1}/{months}",
expense, credit, release)amortize.py を含むディレクトリからこのコマンドブロックを実行します。
python3 amortize.py insurance > insurance.beancount
uv run --no-project --with beancount==3.2.3 bean-check insurance.beancount支払いは、当座預金を 600.00 USD 貸方記帳し、前払保険料を同額借方記帳します。各リリースは、費用を借方記帳し、前払保険料を 100.00 USD 貸方記帳します。リリースは6回で、2024年6月1日、7月1日、8月1日、9月1日、10月1日、11月1日です。前払残高は、6月のリリース後 500.00 USD、7月のリリース後 400.00 USD、11月のリリース後はゼロになります。
実践的な例
年間ソフトウェアライセンス
同じ保存済みスクリプトを使用して、別のスタンドアロンのソフトウェア例を生成します。
python3 amortize.py software > software.beancount
uv run --no-project --with beancount==3.2.3 bean-check software.beancount1,200ドルのライセンス支払いは2024年1月15日です。12回のリリースが 100.00 USD で2024年1月15日から12月15日まで実行されます。この例では、各月の開始時に丸1ヶ月分を計上します。1月は日割り計算しません。最後のリリース後、Assets:Prepaid:Software はゼロになり、Expenses:Software:Adobe の合計は 1200.00 USD になります。
専門サービスリテイナー
この別の例では、1月5日の4,500ドルの支払いを、1月、2月、3月に均等に消費される前払い料金として扱います。
python3 amortize.py retainer > retainer.beancount
uv run --no-project --with beancount==3.2.3 bean-check retainer.beancount2024年1月5日、2月5日、3月5日付けの 1500.00 USD の3回のリリースにより、Assets:Prepaid:Professional はゼロになり、Expenses:Professional:Legal は 4500.00 USD になります。サービス提供に応じて獲得されるリテイナーの場合は、この前提を実際のサービススケジュールに置き換えてください。
設備の減価償却(固定資産)
固定資産の減価償却では、購入原価を保持するために償却累計額勘定(コントラ勘定)を使用します。この例では、耐用年数3年、残存価値ゼロ、2024年1月20日からの月次全額計上を想定しています。
python3 amortize.py equipment > equipment.beancount
uv run --no-project --with beancount==3.2.3 bean-check equipment.beancount購入は Assets:Equipment:Computers:Cost を 3000.00 USD 一度だけ借方記帳します。36回のリリースは Expenses:Depreciation:Computers を借方記帳し、Assets:Equipment:Computers:AccumDep を貸方記帳します。リリース1〜35は 83.33 USD です。2026年12月20日の36回目のリリースは 83.45 USD です。したがって、35 × 83.33 + 83.45 = 3000.00 となります。全36回を 83.33 USD にすると、0.12 USD が減価償却されずに残ります。
完了時点で、原価は 3000.00 USD のまま、減価償却累計額は -3000.00 USD となり、純簿価はゼロになります。設備がまだ記録されている間、コントラ勘定自体はゼロに戻りません。
レポートと検証
1. アサーションによる前払残高の監視
Beancountは、その日の取引の前、つまりその日の開始時点で残高をチェックします。この文脈に沿ったアサーションブロックを生成された insurance.beancount に追加し、その bean-check コマンドを再実行します。
2024-06-02 balance Assets:Prepaid:Insurance 500.00 USD
2024-07-02 balance Assets:Prepaid:Insurance 400.00 USD
2024-07-02 balance Expenses:Insurance:Auto 200.00 USD
2024-11-02 balance Assets:Prepaid:Insurance 0.00 USD
2024-11-02 balance Expenses:Insurance:Auto 600.00 USD7月2日は、2回のリリース(6月1日と7月1日)の後です。7月2日に 500.00 USD というアサーションは正しくありません。これらのアサーションには生成された保険元帳が必要です。これらはスタンドアロンの取引ではありません。
2. bean-query による高度な検証
生成された保険ファイルを使用して、この実行可能なコマンドは、排他的な7月2日の締め切りを使用して、7月1日までの累積残高を返します。
uv run --no-project --with beancount==3.2.3 --with beanquery==0.2.0 bean-query insurance.beancount "SELECT account, sum(position) WHERE date < 2024-07-02 AND account ~ '^(Assets:Prepaid:Insurance|Expenses:Insurance:Auto)$' GROUP BY account ORDER BY account"Assets:Prepaid:Insurance が 400.00 USD、Expenses:Insurance:Auto が 200.00 USD になることを期待します。代わりに日付でグループ化すると、累積残高ではなく各日の変動が表示されます。
生成されたファイルをテスト済みのローカルFavaバージョンで表示するには、次を使用します。
uv run --no-project --with beancount==3.2.3 --with beanquery==0.2.0 --with fava==1.30.16 fava insurance.beancountFavaが表示するローカルURLを開きます。設定については、Favaオプションリファレンスを参照してください。レポート期間を明示的に選択してください。ジェネレータは将来の日付を含むスケジュール全体を出力するため、無制限の合計には将来のリリースが含まれます。別の計画ファイルについては、予測シナリオワークフローを参照してください。
制限と最終的なヒント
- 日付は明示的です: 購入日を変更しても、最初のリリースが暗黙的に延期されることはありません。このスクリプトでは、最初のリリースは支払日と同じです。サービス開始が後日の場合は、開始日を別途調整してください。
- 丸めは一度だけ行われます: スクリプトは通常の月次金額をセント単位に丸め、残りを最終リリースに充当します。その調整を維持するために、生成された完全なスケジュールを保持してください。
- 通常のエントリは永続します: これらのリリースは生成されたファイルに保存されます。一度確認して記録してください。同じコストに対して自動償却も有効にしないでください。費用が二重に計上されることになります。
- 会計スケジュールを選択してください: これらは経営管理用の例であり、管轄区域固有の税務ルールではありません。不定期の便益や日割り計算が必要な場合は、実際の金額と日付を計算して記録してください。