2025年12月26日·1分で読めます

照合可能な請求元帳スキーマ:請求書と支払いの照合

請求書、支払い、クレジット、調整を分けて保存する請求元帳スキーマの設計方法。財務が合計を照合・監査しやすくするための原則と実践的な設計図を解説します。

照合可能な請求元帳スキーマ:請求書と支払いの照合

なぜ請求データが照合しなくなるのか

財務にとって「照合できる」とは簡単な約束です:レポートの合計がソースの記録と一致し、すべての数値に辿れる根拠があること。月間で $12,430 を回収したと示すなら、実際に合う支払い(と返金)を特定でき、どの請求書に適用されたかを示し、日付付きの記録であらゆる差分を説明できるべきです。

請求データが照合しなくなる主要因は、データベースが事実ではなく結果を保存してしまうことです。paid_amountbalanceamount_due のような列がアプリケーションロジックで時々更新されます。バグ一つ、リトライ一回、あるいは手動の「修正」で履歴が静かに変わってしまう。数週後には請求書テーブルは請求が「支払い済み」と言うが、支払い行が合わなかったり、対応するクレジットなしで返金が存在したりします。

もう一つのよくある原因は、異なるドキュメント種別を混ぜることです。請求書は支払いではありません。クレジットメモは返金ではありません。調整は割引と同じものではありません。これらを大量のオプション欄のある単一の「transactions」行に押し込むと、レポーティングは推測になり、監査は議論になります。

根本的な不一致は単純です:アプリは現在の状態(「アクセスは有効か?」)を気にする一方で、財務は履歴(「何が、いつ、なぜ起きたか?」)を気にします。請求元帳スキーマは両方をサポートしなければなりませんが、追跡可能性が優先されなければなりません。

目標に向けて設計するポイント:

  • 顧客別、請求書別、会計期間別の明確な合計
  • 変更はすべて新しい行として記録(上書きしない)
  • 請求書から支払い、クレジット、返金、調整への完全な連鎖
  • 生の仕訳から合計を再計算して同じ答えが得られる能力

例:顧客が $100 を支払い、その後 $20 のクレジットを受けたなら、レポートは $100 回収、$20 クレジット、差引 $80 を示すべきで、元の請求額を編集してはいけません。

請求書、支払い、クレジット、調整は分ける

照合できる請求元帳スキーマを作りたければ、各ドキュメント種別を別個のイベントとして扱ってください。混ぜると見た目は整いますが意味があいまいになります。

  • 請求書は請求(顧客が支払うべき金額)です。ヘッダー(顧客、請求番号、発行日、支払期限、通貨、合計)と、売上、数量、単価、税区分といった行アイテムを分けて保存します。高速化のためにヘッダー合計を保存しても構いませんが、常に行から説明できるようにしてください。

  • 支払いは資金移動です(顧客から現金が移る)。カードフローではオーソリゼーション(銀行が承認)とキャプチャ(実際に引き落とし)の区別があります。多くのシステムはオーソリを運用記録として保持し、キャプチャされた支払いだけを元帳に入れ、現金報告を膨らませないようにします。

  • クレジットメモは顧客の債務を減らしますが、必ずしも現金を返すわけではありません。返金は現金の流出です。両者は同時に起こることもありますが、同じものではありません。

  • 調整は現実が記録と一致しないときにチームが行う訂正です。調整には文脈が必要で、誰が作成したか、いつ掲示されたか、理由コード、短いメモを保存してください。例:"四捨五入で 0.03 を償却"、"レガシー残高を移行"。

実用的なルール:"誰もミスをしなければそれが存在するか?" を自問してください。請求書、支払い、クレジットメモ、返金はミスがなくても存在します。調整は稀で、明確にラベル付けされ、レビューしやすくするべきです。

財務が監査できる元帳モデルを選ぶ

照合できる請求元帳スキーマは一つの考えに始まります:ドキュメントは何が起きたかを記述し、元帳の掲示が合計を証明する。請求書、支払い、クレジットメモはドキュメントです。元帳は合計が収まる仕訳の集合です。

ドキュメントと掲示(両方を保存する)

人が読むためにドキュメント(請求ヘッダーと行、支払い受領書、クレジットメモ)を保持してください。しかし、照合の真の根拠としてドキュメント合計だけに頼ってはいけません。

代わりに、各ドキュメントを元帳テーブルに1つ以上の不変の仕訳として掲示します。そうすれば財務は口座、顧客、通貨、掲示日で仕訳を集計して毎回同じ答えを得られます。

監査に優しい単純なモデルにはいくつかのルールがあります:

  • 不変の仕訳:掲示済み金額は編集しない。変更は新しい仕訳で行う。
  • 明確な掲示イベント:各ドキュメントは一意の参照を持つ掲示バッチを作る。
  • バランスする論理:仕訳は適切に相殺される(会社レベルで借方と貸方が一致することが多い)。
  • 日付を分ける:ドキュメント日(顧客に見せる日)と掲示日(報告に反映される日)を分けて保持する。
  • 安定した参照:外部参照(請求番号、支払いプロセッサのID)を内部IDと並べて保存する。

自然キーと代理ID

結合やパフォーマンスには代理IDを使いつつ、マイグレーションや再インポートに耐える安定した自然キーも保存してください。財務はデータベースIDが変わった後でも「Invoice INV-10483」を要求します。請求番号やプロバイダID(支払いプロセッサのチャージIDなど)を一級フィールドとして扱ってください。

履歴を残したまま取り消す

元に戻す必要があるときは、削除や上書きはしないでください。逆の仕訳を掲示して元の金額と逆符号の新しい仕訳を作り、それを元の掲示にリンクします。

例:誤った請求書に $100 が適用された場合は、誤適用の掲示を取り消す(逆仕訳を投稿)し、その後正しい請求書に再適用する新しい掲示を行います。

手順別スキーマ設計図(テーブルとキー)

請求元帳スキーマは、各ドキュメント種別が独自のテーブルを持ち、後で関係を推測するのではなく明示的な割当レコードでつなぐと照合性が高まります。

コアとなる小さなテーブルセットから始め、各テーブルは明確な主キー(UUIDやbigserial)と必須の外部キーを持ちます:

  • customers: customer_id (PK)、external_ref のような安定識別子(ユニーク)
  • invoices: invoice_id (PK)、customer_id (FK)、invoice_number (unique)、issue_datedue_datecurrency
  • invoice_lines: invoice_line_id (PK)、invoice_id (FK)、line_typedescriptionqtyunit_pricetax_codeamount
  • payments: payment_id (PK)、customer_id (FK)、payment_datemethodcurrencygross_amount
  • credits: credit_id (PK)、customer_id (FK)、credit_number (unique)、credit_datecurrencyamount

次に合計を監査可能にするテーブル(割当て)を追加します。支払いやクレジットは複数の請求書をカバーでき、請求書は複数の支払いで支払われ得ます。

結合テーブルは複合キーだけでなく独自のキーを持つようにします:

  • payment_allocations: payment_allocation_id (PK)、payment_id (FK)、invoice_id (FK)、allocated_amountposted_at
  • credit_allocations: credit_allocation_id (PK)、credit_id (FK)、invoice_id (FK)、allocated_amountposted_at

最後に、調整は分けて保持して財務が何が変わったか・なぜかを見られるようにします。adjustments テーブルは対象レコードを invoice_id(NULL可能)で参照し、履歴を書き換えずにデルタ金額を保存します。

資金を掲示するところには監査フィールドを追加します:

  • created_at, created_by
  • reason_code(write-off, rounding, goodwill, chargeback)
  • source_system(manual, import, Stripe, support tool)

クレジット、返金、償却と壊れない合計

請求元帳アプリを構築する
PostgreSQLで照合可能な請求元帳をモデル化し、すべての仕訳を追跡可能にします。
構築を開始

ほとんどの照合問題は、クレジットや返金が「負の支払い」として記録されたり、償却が請求書行に混ぜられたりすることで始まります。クリーンな請求元帳は各ドキュメント種別を独自のレコードとして保持し、唯一合流するのは明示的な割当てだけにします。

クレジットは、なぜ顧客の債務を減らしたのかを示すべきです。単一の請求書に適用するなら1つのクレジットメモを作り、それをその請求書に割り当てます。複数の請求書に跨るなら同じクレジットメモを複数の請求書に割り当てます。クレジットは1つのドキュメントであり、多数の割当てを持てます。

返金は支払いの逆であり「負の支払い」ではありません。返金は現金が出て行くイベントなので、それ自体を別のレコード(しばしば元の支払いに参照を持つ)として扱い、支払いと同様に割り当てを行います。これにより、銀行明細に受領と返金双方が表示されたときに監査トレイルが明確になります。

分割支払いや部分クレジットも同様に扱います:支払いやクレジットの総額を1行に持ち、それぞれの請求書にどれだけ適用したかを割当て行で記録します。

二重計上を防ぐ掲示ルール

これらのルールで多くの「謎差分」を排除できます:

  • 支払いを負の値で保存しない。返金レコードを使う。
  • 請求書合計を掲示後に減らさない。クレジットメモや調整を使う。
  • ドキュメントは一度掲示し(posted_at)、掲示後に金額を編集しない。
  • 請求残高を変更するのは掲示済み割当ての合計だけにする。
  • 償却は理由コードを持つ調整で、請求書に対してクレジットと同様に割当てる。

税金、手数料、通貨、丸めの取り扱い

多くの照合問題は再現できない合計から始まります。最も安全なルールは単純です:請求を作った元の行(raw lines)を保存し、顧客に提示した合計も保存すること。

税金と手数料:行レベルで保持する

税や手数料は行ごとに保存し、請求書レベルのサマリーだけにしないでください。異なる製品で税率が違ったり、手数料が課税対象だったり、免税が請求書の一部にだけ適用されることがあります。tax_total のみを保持すると、やがて説明できないケースにぶつかります。

保持すべきもの:

  • 生の行(何を売ったか、qty、unit price、discount)
  • 計算済み行合計(line_subtotalline_taxline_total
  • 請求書サマリー合計(subtotaltax_totaltotal
  • 使用した税率と税種別
  • 手数料は独立した行アイテム(例:「決済処理手数料」)として

これにより財務は合計を再構築し、税計算が常に同じ方法で行われたことを確認できます。

多通貨:発生した事象と報告方法の両方を保存する

複数通貨をサポートするなら、トランザクション通貨と報告通貨の両方の値を記録してください。最低限、すべての金額ドキュメントに currency_code を持たせ、掲示時に使用した fx_rate と、帳簿通貨での表示用金額(例:amount_reporting)を保持します。

例:顧客に 100.00 EUR と 20.00 EUR の VAT を請求する場合、EUR の行と合計を保存し、請求掲示時に使用した fx_rate と換算された報告合計も保存します。

丸めは独自の扱いを必要とします。丸めルールを1つ(行ごとまたは請求書ごと)決めて一貫して運用してください。丸め差が出る場合は、それを丸め調整行(または小額の調整エントリ)として明示的に記録し、合計を黙って変更しないでください。

ステータス、掲示日、保存すべきでないもの

照合ワークスペースを作る
ドキュメントと割当てを並べて表示する照合ビューを構築し、レビューを迅速化します。
プロジェクトを開始

ステータスを会計的真実のショートカットに使うと照合が混乱します。ステータスはワークフローラベルとして扱い、掲示済みの元帳エントリを会計のソースオブトゥルースにしてください。

ステータスは厳格で退屈なものにします。それぞれが「このドキュメントは合計に影響を与えるか?」に答えるべきです。

  • Draft: 内部のみ、掲示されておらずレポートに含めない
  • Issued: 確定して送付済み、掲示の準備完了(または既に掲示)
  • Void: キャンセル、掲示済みなら取り消しが必要
  • Paid: 掲示済みの支払いとクレジットで完全に精算済み
  • Refunded: 返金が掲示され現金が戻された

日付は多くのチームが想定より重要視していません。財務は「これはどの月に属するのか?」と尋ねるので、回答がUIの操作ログによって左右されるべきではありません。

  • issued_at: 請求書が確定した日時
  • posted_at: 会計報告に計上される日時
  • settled_at: 資金が清算された、または支払いが確定した日時
  • voided_at / refunded_at: 取り消しや返金が有効になった日時

真実として保存してはいけないもの:元帳から再構築できない派生値。balance_dueis_overduecustomer_lifetime_value のようなフィールドは、常に invoices、payments、credits、allocations、adjustments から再計算できるならキャッシュとして保存しても構いませんが、それができないと脆弱です。

小さな例:支払いのリトライがゲートウェイに2回送られたとします。冪等キー(idempotency_key)がないと、2つの支払いが保存され請求書が「支払い済み」とマークされ、財務は余分な $100 を見ることになります。外部チャージ試行ごとに一意の idempotency_key を保存し、データベースレベルで重複を拒否してください。

財務が初日から期待するレポート

財務業務を安全にする
組み込みの認証モジュールで、財務操作を制御可能かつ監査可能にします。
認証を追加

請求元帳スキーマは、財務が基本的な質問に素早く答えられ、毎回同じ合計を得られると証明されます。

多くのチームは次から始めます:

  • 売掛金エイジング:顧客別・年齢バケット(0-30, 31-60 等)別の未回収金額
  • 受取現金:支払いの掲示日ベースで日次・週次・月次の回収額
  • 収益対現金:請求書掲示と支払い掲示の比較
  • エクスポートのための監査トレイル:GL行からその行を作った正確なドキュメントと割当て行にドリルバックできること

エイジングは割当てが最も重要になる場所です。エイジングとは「請求書合計マイナス支払い合計」ではありません。それは「ある日付時点で各請求書に残っている未決金額」です。これには、各支払い、クレジット、調整がどの請求書にいつ割り当てられたかを保存する必要があります。

受取現金は支払いテーブルで駆動されるべきで、請求書ステータスではありません。顧客は早く払うことも遅く払うことも部分的に払うこともあります。

収益対現金は請求書と支払いを分けておく理由です。例:3月30日に $1,000 の請求を発行し、4月5日に $600 を受け取り、4月20日に $100 のクレジットを発行したとします。収益は3月に属し(請求の掲示)、現金は4月に属し(支払いの掲示)、クレジットは掲示時に売掛金を減らします。割当てがそれらを結びつけます。

例シナリオ:1顧客、4種類のドキュメント

1人の顧客、1か月、4種類のドキュメント。各ドキュメントは一度だけ保存され、資金は割当てテーブル(時には "applications" と呼ばれる)を通って動きます。これにより最終残高は再計算しやすく、監査もしやすくなります。

顧客 C-1001 (Acme Co.) を仮定します。

作成するレコード

invoices

invoice_idcustomer_idinvoice_dateposted_atcurrencytotal
INV-10C-10012026-01-052026-01-05USD120.00

payments

payment_idcustomer_idreceived_atposted_atmethodamount
PAY-77C-10012026-01-102026-01-10card70.00

credits(クレジットメモ、善意のクレジット等)

credit_idcustomer_idcredit_dateposted_atreasonamount
CR-5C-10012026-01-122026-01-12service issue20.00

adjustments(事後の訂正、売上ではない)

adjustment_idcustomer_idadjustment_dateposted_atnoteamount
ADJ-3C-10012026-01-152026-01-15underbilled fee5.00

allocations(これが実際に残高を照合する)

allocation_iddoc_type_fromdoc_id_fromdoc_type_todoc_id_toposted_atamount
AL-900paymentPAY-77invoiceINV-102026-01-1070.00
AL-901creditCR-5invoiceINV-102026-01-1220.00

請求書残高の計算方法

INV-10 の未収残高はソース行から監査人が再計算できます:

open_balance = invoice.total + sum(adjustments) - sum(allocations)

したがって:120.00 + 5.00 - (70.00 + 20.00) = 35.00 が未払金です。

「35.00」を辿る手順:

  • 請求書合計(INV-10)から始める
  • 同じ請求書に紐づく掲示済み調整(ADJ-3)を加える
  • 請求書に適用された各掲示済み割当て(AL-900、AL-901)を差し引く
  • 各割当てが実際のソースドキュメント(PAY-77、CR-5)を指していることを確認する
  • タイムラインを説明するために各 posted_at と日付を検証する

照合を壊す一般的なミス

掲示と取り消しを自動化する
掲示ルール、理由コード、承認をドラッグ&ドロップのビジネスロジックで追加します。
ワークフローを構築

多くの照合問題は「算術バグ」ではありません。ルールの欠如が原因で、同じ現実の出来事が関わった人によって異なる方法で記録されてしまいます。

一般的な落とし穴は負の行をショートカットとして使うことです。負の請求行、負の支払い、負の税行はすべて異なる意味を持ち得ます。負数を許容するなら、1つの明確な取り消しポリシーを定義してください(例:元の行を参照する逆仕訳のみを使い、逆符号の意味と割引の意味を混同しない)。

もう一つ頻繁に起きるのは履歴の変更です。請求書を発行したら後で価格や住所を編集して合わせないでください。元のドキュメントを保持し、変更を説明する調整やクレジットを掲示してください。

合計を壊しやすいパターン:

  • 参照元の行に戻る明確な参照を持たない負の行を許すこと
  • 発行済み後に古い請求書を編集して訂正しないで、調整やクレジットを掲示すること
  • ゲートウェイ取引IDと内部IDをマッピングテーブルなしで混在させ、真のソースを曖昧にすること
  • サポート行(税、手数料、丸め、割当て)が欠けているのにアプリケーションコードに合計の計算をさせること
  • 「資金が動いたこと」を「どの請求書に支払ったか(割当て)」と分離して保存しないこと

最後の点が最も混乱を招きます。例:顧客が $100 を支払い、その後 $60 を請求書Aに、$40 を請求書Bに適用したとします。支払いは1つの資金移動ですが、2つの割当てが発生します。もし「支払い = 請求書」という単純な保存しかしていないと、分割支払いや過剰支払い、再割当てをサポートできません。

チェックリストと次のステップ

機能を追加する前に、基本が成立していることを確認してください。請求元帳スキーマが照合できるのは、すべての合計が特定の行に辿れ、すべての変更に監査トレイルがあるときです。

クイック照合チェック

小さなサンプル(1人の顧客、1か月)と全データセットでこれらを実行してください:

  • レポートのすべての掲示済み数値がソース行(請求書行、支払い、クレジットメモ、調整)に辿れ、掲示日と通貨がある。
  • 割当ては適用先のドキュメントを超えない(支払いの割当て合計は支払い総額以下、クレジットも同様)。
  • データは削除されない。誤ったエントリは理由を付けた逆仕訳で取り消し、訂正は新しい掲示行で行う。
  • 未収残高は導出可能で保存しない(請求書の未収額 = 請求書合計 - 掲示済み割当てとクレジット)。
  • ドキュメント合計は行と一致する(請求ヘッダー合計は行合計、税、手数料、選んだ丸めルールに基づく合計と一致)。

出荷可能なものにするための次のステップ

スキーマが固まったら、そこに運用ワークフローを構築してください:

  • 請求書、支払い、クレジット、調整の作成、掲示、取り消しを必須メモ付きで行う管理画面
  • ドキュメントと割当てを並べて表示する照合ビュー(誰がいつ掲示したかを含む)
  • 財務が期待するエクスポート(掲示日別、顧客別、GLマッピング別)
  • 期末クローズワークフロー:閉鎖済み月の掲示日をロックし、遅い修正は逆仕訳で対応させる
  • テストシナリオ(返金、分割支払い、償却)が期待合計と一致することを検証する

もし内部向けの迅速な財務ポータルを目指すなら、AppMaster (appmaster.io) はPostgreSQLスキーマのモデリング、API生成、管理画面の生成を支援できます。これにより掲示と割当てのルールがアプリ進化の中で一貫して保たれます。

よくある質問

請求データにおける「照合」とは実際に何を意味しますか?

照合とは、報告された合計がソースの記録から再構築でき、日付付きの仕訳に遡って追跡できることを意味します。レポートが $12,430 を回収したと示しているなら、その金額に合致する掲示済みの支払いと返金を正確に指し示せるべきで、上書きされたフィールドに頼るべきではありません。

なぜ請求の合計が時間とともに合わなくなるのですか?

最も一般的な原因は、paid_amountbalance_due のように変化する「結果」を事実として保存してしまうことです。そうしたフィールドがリトライ、バグ、手動編集で更新されると履歴が失われ、合計が実際の出来事と一致しなくなります。

請求書、支払い、クレジット、返金を1つの「transactions」テーブルに入れてはいけないのはなぜですか?

それぞれが異なる現実世界の出来事であり、会計上の意味合いが違うからです。単一の「transactions」レコードに詰め込んでオプション項目で表すと、行が何を表すのか曖昧になり、レポートは推測に、監査は議論になります。

クレジットメモと返金の違いは何ですか?

クレジットメモは顧客の債務を減らしますが、必ずしも現金が戻るわけではありません。返金は現金の流出で、通常は以前の支払いに紐づきます。両者を同じもの(または負の支払い)として扱うと、現金報告や銀行突合せが非常に難しくなります。

履歴を書き換えずに請求のミスを直すにはどうすればいいですか?

編集や削除の代わりに取り消し(reversal)を掲示してください。元の金額を逆符号で反映する新しい仕訳を作り、それを元の掲示にリンクし、続けて訂正された割当てを掲示すると、監査トレイルに何がいつ、なぜ変わったかが明確に残ります。

分割払いや1つの支払いが複数の請求書をカバーする場合はどう扱えばいいですか?

支払いまたはクレジットを1つ以上の請求書に接続する明示的な割当てレコード(application)を使い、割当て金額と掲示日時を記録します。請求書の未収残高は、請求書合計と調整額の合計から掲示済み割当てを差し引いて計算できるようにします。

月次の報告を一貫させるために、どの日時を保存すべきですか?

ドキュメント日と掲示日(posting date)の両方を保持してください。ドキュメント日が顧客に見せる日付で、掲示日が財務レポートや期末にいつ計上されるかを制御します。これにより、誰かが後から編集しても月次集計が変わらないようにできます。

税金と手数料は請求書レベルで保存すべきですか、それともラインアイテムごとですか?

税金と手数料はラインレベルで保存し、顧客に提示した正確な合計も保持してください。請求書レベルの tax_total のみを残すと、混合税率や免税などのケースで再現できなくなります。

合計を再現できるように多通貨と丸めはどう保存すべきですか?

取引通貨の金額を保存し、掲示時に使用したFXレートを記録して帳簿通貨での換算額も保持してください。丸めルールは1つ決めて(行ごとまたは請求書ごと)、丸め差分は明示的な丸め調整行として記録しておくと、合計を正確に再現できます。

レポートのために請求書の「ステータス」(Paid/Void)に頼れますか?

ステータスはワークフローラベルとして扱い、会計的な真実は掲示済みの仕訳と割当てに委ねてください。ステータスは間違うことがあるので、不変の掲示エントリがあれば財務は同じ方法で毎回合計を再計算できます。

始めやすい
何かを作成する 素晴らしい

無料プランで AppMaster を試してみてください。
準備が整ったら、適切なサブスクリプションを選択できます。

始める