銀行エンジニアリング 03:取消仕訳と訂正仕訳
間違えた記帳は消しません。反対の仕訳を追加して打ち消し、必要なら正しい金額で記帳し直します。その理由と、MiniBankが二重取消をどう防ぐかを学びます。
v8以降に実装した台帳・記帳エンジンなどを実際に動かし、正常時と異常時の両方から銀行システムの構造を学ぶ。
Prerequisite: BANKING SYSTEMLEARNING GOALS
このページで学ぶこと
- 取消(Reverse)と訂正(Correct)の違い
- 元の仕訳を残す理由
- 二重取消・取消の取消を防ぐ仕組み
PLAIN LANGUAGE
まず、ここだけつかむ
間違えた仕訳は消さず、貸借を反転した取消仕訳を追加して打ち消します。
訂正は、取消と正しい金額での再記帳を1つのトランザクションで行います。
同じ仕訳の取消は1回だけで、取消の取消はできません。
DIFFICULT PARTS, STEP BY STEP
難しいポイントを、順番にほどく
専門用語を覚えることより、「なぜ必要か」「このシステムのどこで使うか」を理解することが目標です。
Reverse Entry
元仕訳の借方と貸方を入れ替えた仕訳です。
記録を消さずに効果だけを打ち消すためです。
posting.reverse_event()。reversal_of_entry_id で元仕訳を指します。
Correcting Entry
取消のあと正しい内容で記帳し直すことです。
誤り・取消・正解の3つを追跡可能に残すためです。
posting.correct_event()。corrects_event_id で元イベントを指します。
二重の防御
アプリの確認とDBの一意制約の両方で守ることです。
同時実行の隙間を制約で塞ぐためです。
reverses_event_id と reversal_of_entry_id がどちらも一意です。
Level 1 基礎:消しゴムではなく赤ペン
紙の帳簿で間違えたとき、消しゴムで消すと「何を間違えたか」が分からなくなります。銀行の台帳では、元の行を残したまま、借方と貸方を入れ替えた行を追加して打ち消します。これが取消仕訳(Reverse Entry)です。
Level 2 銀行業務:手数料を1,100円と誤って徴収した
本来110円の手数料を1,100円で記帳してしまった場合、MiniBankでは「訂正」を使います。訂正は、誤ったイベントの取消と、正しい金額での再記帳を1回の操作(1つのトランザクション)で行います。
| 順 | イベント | 区分 | 仕訳 | 顧客の預金 |
|---|---|---|---|---|
| 1 | SERVICE_FEE_CHARGE 1,100円 | 通常(ORIGINAL) | 借方:顧客預金 / 貸方:FEE_REVENUE | −1,100 |
| 2 | EVENT_REVERSAL 1,100円 | 取消(REVERSAL) | 1の貸借を反転 | +1,100 |
| 3 | SERVICE_FEE_CHARGE 110円 | 訂正(CORRECTION) | 借方:顧客預金 / 貸方:FEE_REVENUE | −110 |
Level 3 システム:MiniBankでの実装(正常時)
- posting.reverse_event():元仕訳の明細の借方・貸方を入れ替えた仕訳を作り、reversal_of_entry_id で元仕訳を指す
- posting.correct_event():取消と訂正イベントの記帳を同じトランザクションで行う。訂正イベントは corrects_event_id で元イベントを指す
- 取消・訂正は管理責任者(admin_manager)だけが実行でき、理由の入力が必須
- トレース画面の「取消・訂正の連鎖」で、元・取消・訂正の3件を並べて確認できる
異常時:同じイベントを2回取り消そうとする
| 段階 | 内容 |
|---|---|
| 症状 | 取消ボタンを別々の担当者がほぼ同時に押した |
| 起きること | 2回目は PE011 で拒否される。仮にアプリ側の確認をすり抜けても、仕訳テーブルの reversal_of_entry_id が一意制約のため、同じ仕訳の取消は台帳レベルで1件しか入らない |
| 取消の取消 | REVERSAL 区分のイベントを取り消そうとすると PE011。打ち消しをさらに打ち消す連鎖は作らせない |
| 残高不足 | 入金を取り消すと顧客残高がマイナスになる場合は PE010 で拒否(預金の cached_balance は0未満にできない) |
Level 4 アーキテクチャ:なぜ二重の防御にするのか
アプリケーションの事前確認(すでに取消済みか)だけでは、同時実行の隙間で2件目が通る可能性があります。MiniBankは事前確認に加えて、DBの一意制約という「最後の砦」を持たせ、どの経路から呼ばれても台帳の不変条件が守られるようにしています。
どこを確認すればよいか
- 管理画面「Ledger・Posting」→ イベントのトレース → 取消・訂正の連鎖
- 仕訳帳で reversal_of_entry_id を持つ仕訳
CHECK YOUR UNDERSTANDING
3問で理解チェック
答えを頭の中で考えてから、各項目を開いて確認してください。
Q1取消した元の仕訳はDBから消えますか?
消えません。取消仕訳が追加されるだけです。
Q2同じイベントを2回取り消すとどうなりますか?
PE011で拒否されます。
Q3取消・訂正を実行できるロールは?
管理責任者(admin_manager)だけです。
完全に暗記する必要はありません。大切な考え方を説明できそうなら押してください。
SOURCE TRAIL
根拠と関連教材
CURRENT IMPLEMENTATIONは確認したrepository内の実装です。HISTORICAL IMPLEMENTATIONは導入・修正の履歴で、後続migrationによる再定義があり得ます。RELATED LESSONは教材への案内で、実装の一次Sourceではありません。ASSUMPTIONは仮定、UNKNOWNは未確認を表します。
確認基点: d02eae8914f39cbf06bfe422dc39c71886f82b3e / 2026-09-11。稼働環境への適用確認: UNKNOWN。パス実在の自動検査と、記述した技術的事実の確認は別です。
Implementation Status: IMPLEMENTED IN MINIBANK(この教材が扱うコードの範囲)
- RELATED LESSON/docs/be-posting-engineBusiness EventとPosting Rule
- RELATED LESSON/docs/concurrency-control同時実行と競合制御
- CURRENT IMPLEMENTATION
supabase/migrations/20260924100000_v8_posting_engine.sqlposting.reverse_event / posting.correct_event取消仕訳と訂正仕訳 - CURRENT IMPLEMENTATION
scripts/banking/v8-posting.test.mjs冪等性・同時実行・取消・訂正・整合性検出のDBテスト