T+2の照合とカード承認・売上確定の点検
目標
休場日の表を読んで、営業日基準のT+2の決済日を再計算して間違った約定を探し、約定の帳簿と決済の帳簿を4方向で突合し、未決済を理由別に分けて金額まで出し、カードのオーソリと売上確定の差を残さず説明して、二重請求を見つけ出せるようになります。
なぜ重要なのか
証券のT+2とカードのオーソリ・売上確定は、別のドメインですが、構造が同じです。出来事が2つに分かれていて、その間に状態が生きており、その状態を監視しなければ、お金が漏れます。このラボは、その2つの構造を1周ずつ回ってみます。
このラボが強制する4つは、すべて現場の規則です。休場日はデータとして置きます。コードに埋め込むと、臨時休日が指定されるたびにデプロイが必要になり、デプロイが遅れれば、その週に事故が起きます。突合は、件単位で双方向に行います。合計だけを比較すると、2つの方向の差が互いを打ち消します。未決済は理由で分けます。まとめて数えると、担当部署が決まらず、誰も処理しません。二重請求は冪等キーで探します。オーソリ番号では、永遠に出てきません。
今回の事案は次のとおりです。清算チームから、9月第2週の未決済残高が普段の3倍だと連絡があり、同じ週に、特定の加盟店の二重請求の苦情が集中しました。基準日は2026-09-16です。
営業日の計算規則は次のとおりです。約定日の翌日から1日ずつ進みながら、土曜日・日曜日ではなく、holidaysテーブルにない日を営業日として数え、2番目の営業日が決済日です。休場日は必ずholidaysテーブルから読んでください。コードに埋め込むと、このラボの要点をそのまま見逃します。
ステップ
/root/cap/settleを作成し、正解の生成スクリプトをそのまま実行して、/root/cap/settle/settle.db、/root/cap/settle/auth.jsonl、/root/cap/settle/capture.jsonlを作ってください。holidaysテーブルを読んで、営業日基準のT+2を再計算してください。/root/cap/settle/calendar.txtにtrades=、holidays=、bad_settle_date=、settle_on_nonbusiness=を、/root/cap/settle/baddate.csvにtrade_id,trade_date,recorded_settle_date,correct_settle_dateを書いてください。tradesとsettlementsを突合してください。/root/cap/settle/recon.txtにtrades=、settlements=、amount_matched=、amount_mismatch=、amount_mismatch_total=、missing_settlement=、orphan_settlement=、orphan_amount=の8行を、/root/cap/settle/amountdiff.csvにtrade_id,trade_amount,settled_amount,diffを書いてください。- 決済日が
2026-09-16より前なのに決済が終わっていない約定を探して、/root/cap/settle/fails.csvにtrade_id,settle_date,amount,settlement_statusで、/root/cap/settle/fails.txtにfail_count=、fail_amount=、no_record=、pending=、failed=で書いてください。決済記録がそもそもなければ、状態をnoneと書きます。 /root/cap/settle/auth.txtに8行書いてください。auths=、captures=、approved=、voided=、declined=、full_capture=、partial_capture=、no_capture=です。/root/cap/settle/orphan.csvに、売上確定のないapprovedのオーソリをauth_id,merchant,amount,tsで書き、/root/cap/settle/orphan.txtにno_capture_count=、no_capture_amount=、partial_count=、partial_remaining_amount=を書いてください。idempotency_keyでまとめて、オーソリが2件以上あるキーを探し、/root/cap/settle/dupcharge.csvにidempotency_key,auth_ids,charged_amountで書き、/root/cap/settle/dupcharge.txtにdup_keys=、double_charged_amount=を書いてください。auth_idsは、パイプ(|)でつなぎます。/root/cap/settle/report.mdにレポートを書いてください。## 무슨 일이 있었나、## 결제일 계산、## 대사 결과、## 미결제、## 카드 승인과 매입、## 무엇을 고쳐야 하나の6つの節が必要です(見出しは韓国語で、順に「何があったか」「決済日の計算」「突合結果」「未決済」「カードのオーソリと売上確定」「何を直すべきか」という意味です)。
参考
- DBは
sqlite3 -readonly fileで読んでください。Pythonではsqlite3.connect('file:...?mode=ro', uri=True)です。 - 金額はすべて整数のウォン単位です。実数で扱うと、合計が微妙にずれて採点で落ちます。
- 日付の比較は、
YYYY-MM-DDの文字列どうしをそのまま比較しても正確です。 - よくある間違い1: ステップ2で、休場日をコードに埋め込んでしまいます。テーブルに含まれる日が何日かも、数える必要があります。
- よくある間違い2: ステップ4で、日付の条件を抜かしてしまいます。まだ決済日が来ていない件まで数えると、残高が膨らみます。
- よくある間違い3: ステップ7で、2つのオーソリの金額をどちらも足してしまいます。1つ目は正常な請求なので、2つ目以降だけが二重請求です。
約定・決済の元帳とカードログを作る
/root/cap/settleを作成し、正解の生成スクリプトをそのまま実行して、/root/cap/settle/settle.db、/root/cap/settle/auth.jsonl、/root/cap/settle/capture.jsonlを作ってください。
生成スクリプトをそのまま実行すれば、sqlite DB 1つとJSONL 2つが作られます。シードを変えると、採点値とずれます。
営業日基準のT+2で決済日を検証する
holidaysテーブルを読んで、営業日基準のT+2を再計算してください。/root/cap/settle/calendar.txtにtrades=、holidays=、bad_settle_date=、settle_on_nonbusiness=を、/root/cap/settle/baddate.csvにtrade_id,trade_date,recorded_settle_date,correct_settle_dateを書いてください。
休場日はコードに埋め込まず、holidaysテーブルから読んでください。週末と休場日を飛ばしながら、営業日を2回数えれば済みます。
約定の帳簿と決済の帳簿を双方向に突合する
tradesとsettlementsを突合してください。/root/cap/settle/recon.txtにtrades=、settlements=、amount_matched=、amount_mismatch=、amount_mismatch_total=、missing_settlement=、orphan_settlement=、orphan_amount=の8行を、/root/cap/settle/amountdiff.csvにtrade_id,trade_amount,settled_amount,diffを書いてください。
4つの方向を別々に数えてください。件数の合計だけを比較すると、2つの方向の差が互いを打ち消します。
未決済を理由別に分ける
決済日が2026-09-16より前なのに決済が終わっていない約定を探して、/root/cap/settle/fails.csvにtrade_id,settle_date,amount,settlement_statusで、/root/cap/settle/fails.txtにfail_count=、fail_amount=、no_record=、pending=、failed=で書いてください。決済記録がそもそもなければ、状態をnoneと書いてください。
基準日は2026-09-16です。決済日がそれより前の約定だけが対象で、決済記録がそもそもないものも未決済です。
オーソリと売上確定の差を理由別に説明する
/root/cap/settle/auth.txtに8行書いてください。auths=、captures=、approved=、voided=、declined=、full_capture=、partial_capture=、no_capture=です。
オーソリごとに売上確定金額の合計を求めて、3つに分けてください。合計が0なら売上確定なし、オーソリ金額より少なければ一部売上確定、同じか大きければ全額売上確定です。
売上確定のないオーソリと一部売上確定の残額を出す
/root/cap/settle/orphan.csvに、売上確定のないapprovedのオーソリをauth_id,merchant,amount,tsで書き、/root/cap/settle/orphan.txtにno_capture_count=、no_capture_amount=、partial_count=、partial_remaining_amount=を書いてください。
オーソリ取消や拒否の件は、ここには入りません。statusがapprovedなのに売上確定がないものだけです。
冪等キーで二重請求を探す
idempotency_keyでまとめて、オーソリが2件以上あるキーを探し、/root/cap/settle/dupcharge.csvにidempotency_key,auth_ids,charged_amountで書き、/root/cap/settle/dupcharge.txtにdup_keys=、double_charged_amount=を書いてください。auth_idsは、パイプ(|)でつなぎます。
auth_idでまとめると、何も出てきません。idempotency_keyでまとめて、2件以上あるものを見てください。二重請求額は、2つ目以降のオーソリが売上確定した金額です。
決済突合レポートを書く
/root/cap/settle/report.mdにレポートを書いてください。## 무슨 일이 있었나、## 결제일 계산、## 대사 결과、## 미결제、## 카드 승인과 매입、## 무엇을 고쳐야 하나の6つの節が必要です(見出しは韓国語で、順に「何があったか」「決済日の計算」「突合結果」「未決済」「カードのオーソリと売上確定」「何を直すべきか」という意味です)。
6つの節が必要です。突合の節には2つの方向の数字がどちらも、対処の節には営業日の計算と冪等キーの話が、入っている必要があります。