⚠️ 内部資料 / 社外配布禁止
DRAFT — CEO レビュー待ち / 公開前 / 2026-06-10 うーぱん作成
CHAPTER 03 / UPAN / CREDITCARD-CSV-RECONCILE

機能3:クレカ CSV 照合

設計書 v1.0 — 2026-06-10 | うーぱん(A10 経理担当)| AMEXプロトタイプ付き

1. 概要・目的

法人クレジットカードの CSV 明細を 証憑管理簿(14列スプレッドシート)に 自動登録し、既存の受領証憑(レシート・領収書)と突合できる状態を作る機能。

North Star: 「AMEX 明細の GRAB ¥474」と「Drive にある GRAB レシート(VND 76,960)」が I列(突合記号)で 1:1 に紐付いている状態を目指す。

前提:証憑管理簿の位置づけ

  • スプシ ID:1F6PTXD3ckob3EeglnS7gyjSG6RM0CS-PKRaoBwzXK-E タブ名:証憑管理簿
  • 14列(A〜N)構造、sheet_writer_v4.py で書き込む(connect8_ai 認証)
  • Freee への書き込みは今回スコープ外。スプシが叩き台、確定は人間が Freee UI で実施

2. スコープ

項目今回(v1.0)次フェーズ以降
対象カード AMEX のみ(プロトタイプ) 三井住友 / JCB / 楽天 等(アダプタ追加)
CSV 取込 → スプシ登録 設計確定・プロトタイプ実装 LaunchAgent 常駐化
PDF リネーム → Drive 保管 設計のみ(Drive 実書込なし) CEO 承認後に実装
INBOX フォルダ作成 提案のみ(作成は CEO 承認後) 承認次第即時作成可能
突合エンジン(I列埋め) 設計のみ 次フェーズで実装
Freee 連携 スコープ外 Phase C で対応
厳守:主シート「証憑管理簿」本体タブへの書き込みは CEO 承認後のみ。今回はテストタブ _proto_creditcard / dry-run のみ。

3. 全体フロー

3-1. CSV 取込フロー

1
CEO が AMEX 会員サイトから CSV をダウンロード → INBOX_creditcard/ 投入(Drive)
2
うーぱんポーラー(または手動起動)が INBOX_creditcard/ を検知
3
カード種別を自動判定(ファイル名・ヘッダ) → カード別アダプタを選択
4
アダプタが CSV をパース → 共通内部スキーマへ変換
5
dedup チェック:証憑管理簿の既存「クレカ明細」行と (日付+金額+外貨) で重複カット
6
新規行を 証憑管理簿 タブに append(G列=クレカ明細、E列=会社支払 固定)
7
処理済 CSV を _processed/<YYYY-MM>/ へ移動・ログ記録

3-2. PDF 明細保管フロー(設計のみ・実装は承認後)

1
CEO が PDF 明細を INBOX_creditcard/ に投入
2
Codex(MacBook 側)が PDF をリネーム:YYYYMMDD_AMEX_明細_会社支払_クレカ明細.pdf 形式
3
Drive フォルダ 1qmG4ACZ-5H9Qh3R0hzIMkmBNJjZzIDAI(法人クレカ明細(随時保管))へ保管
4
スプシ H列(Drive URL)に HYPERLINK を更新(月次明細 1 行 or 個別明細行に対応付け)

3-3. システム全体図

【投入】
  CEO → INBOX_creditcard/ (Drive)
         ├─ CSV ファイル  → うーぱん CSV パイプライン
         └─ PDF 明細     → Codex リネーム → Drive 保管フォルダ

【CSV パイプライン】
  INBOX_creditcard/
    ↓ カード判定
  カード別アダプタ(amex_adapter.py / smbc_adapter.py[stub] / ...)
    ↓ 共通内部スキーマ
  dedup チェック(日付+金額+外貨 vs 既存クレカ明細行)
    ↓
  sheet_writer_v4.append_row() → 証憑管理簿タブ
    ↓ G列=クレカ明細
  [次フェーズ] reconciler → I列(突合記号)埋め

【証憑管理簿(最終状態のイメージ)】
  row 100: 2026-05-01 | 474 | 76,960 VND | GRAB | 会社支払 | 電子証憑 | 電子その他 | [レシートURL] | ◯ | ...
  row 200: 2026-05-01 | 474 | 76,960 VND | GRAB | 会社支払 | 電子証憑 | クレカ明細  | [明細URL]    | ◯ | ...
                                                                                              ↑ I列で突合

4. マッピング表(確定版)

4-1. AMEX CSV 列定義

列名(CSV)内容備考
ご利用日利用日(例: 04/30)MM/DD 形式、年度は会計年度から補完
データ処理日AMEX が処理した日取込には使わない(発生日は「ご利用日」)
ご利用内容店舗名・サービス名例: GRAB, AMAZON.CO.JP
カード会員様名氏名マスク必須(スプシには書かない)
会員番号#カード番号マスク必須(下4桁のみ備考に記録)
金額日本円請求額(整数)クレカ明細の正式請求額
海外通貨利用金額現地通貨額(例: "9,360 VND")空の場合あり(国内利用)
換算レート為替レート参考値(スプシ N列備考に記録)

4-2. 証憑管理簿 14列へのマッピング

列名マッピング元(AMEX CSV)値の規則
A発生日ご利用日YYYY-MM-DD 形式に変換(年度補完)
B金額(税込)金額JPY 整数・1円単位・丸め禁止
C外貨海外通貨利用金額例: "76,960 VND"。国内は空欄
D店舗・発行者名ご利用内容原文ママ(正規化はしない)
E支払区分固定値会社支払(法人カード固定)
F証憑種別固定値電子証憑(CSV = 電子データ固定)
G証憑形式固定値クレカ明細(CEO確定・VALID_VOUCHER_FORMS 登録済)
HDrive URLPDF 保管後の Drive URLPDF 未保管時は空欄。=HYPERLINK(...) 形式
I突合記号空欄reconciler が後で埋める(次フェーズ)
JFreee deal_id空欄Freee 連携フェーズで埋める
K信頼スコア0.95(固定)CSV パースは高信頼。OCR 誤認なし
L要確認基本空欄dedup 疑いの場合のみフラグ立て
M処理日時実行時刻YYYY-MM-DD HH:MM JST
N備考カード名・元CSV・換算レート例: "AMEX / 20260510_amex.csv / rate:0.006 / card:****1234"
カード番号・氏名の扱い: CSV に含まれる会員番号は下4桁のみ N列備考に記録(例: card:****1234)。 氏名(カード会員様名)はスプシに一切書かない。

5. dedup(重複カット)仕様

5-1. 照合キー

証憑管理簿の既存行のうち G列 = "クレカ明細" の行に対して以下の3軸で照合する。

照合方法備考
発生日(A列)完全一致YYYY-MM-DD 正規化後
金額(B列)完全一致JPY 整数
外貨(C列)数値部分一致(通貨も一致)空欄同士は「一致」扱い

5-2. 判定結果

判定条件処理
重複確定スキップ 3軸すべて一致 スプシへの書き込みをスキップ。ログに「dedup skip row=X」を記録
要確認 日付+金額一致・外貨不一致(例: 同日同額で通貨違い) L列「日付・金額が row X と一致・外貨要確認」を記入。書き込みは実行
通常登録 一致なし 通常 append
AMEX 分割計上パターン: 同日・同店舗で複数行がある場合(例: GRAB 57円+294円+430円=781円 → 別乗車)は 金額が異なるので dedup 対象外。全行を個別登録する。 日付+店舗が一致・金額が異なるケースは部分一致ログのみ記録。

6. 照合(reconciliation)方針

フェーズ分け: 今回(v1.0)は「明細 side 登録」まで。実突合エンジンは次フェーズ。

Phase 1(今回): 明細 side 登録

  • クレカ CSV の各行を G列=「クレカ明細」として証憑管理簿に追加
  • I列(突合記号)は空欄のまま
  • 既存レシート行(G=電子その他 等)とは独立して共存

Phase 2(次フェーズ): 突合エンジン

以下のキーで「クレカ明細行」と「レシート行」を照合し、I列に突合記号を書き込む。

照合優先度キー条件信頼度
金額(JPY)+ 日付(±3日) JPY 完全一致 + 発生日が3日以内 0.9
高(海外) 外貨金額 + 通貨 + 日付(±3日) 外貨数値・通貨一致 + 発生日3日以内 0.95
店舗名(正規化後)+ 日付(±3日) GRAB = grab 等の正規化後一致 0.7
日付(±1日)+ 金額(±5%) ファジー一致。手動確認推奨 0.5

GRAB 分割計上の特殊ルール

問題: AMEX 明細が「1乗車 = 複数行」に分割計上されるケースあり

例: GRAB 57円(9,360 VND)+ 294円(47,840 VND)= 合計 351円(57,200 VND)

対応(Phase 2):

  1. 同日・同店舗の明細行を外貨合計で集計(合計照合モード)
  2. 合計が既存レシート行の外貨と一致 → 複数行まとめて同一突合記号を付与
  3. 合計照合は単一照合の次に試行(単一マッチが優先)

7. カード別 CSV アダプタ設計

7-1. 共通内部スキーマ(CardTransaction)

@dataclass
class CardTransaction:
    use_date:      date        # 発生日(ご利用日)
    amount_jpy:    int         # 日本円請求額(1円単位)
    store_name:    str         # 店舗名(原文)
    foreign_str:   str | None  # 外貨表示文字列 例: "76,960 VND"
    card_label:    str         # カード識別名 例: "AMEX"
    source_file:   str         # 元CSVファイル名
    card_last4:    str | None  # カード下4桁(マスク済)
    fx_rate:       float | None  # 換算レート(参考値)

7-2. アダプタ一覧

カードアダプタ状態備考
AMEX amex_adapter.py 実装済 ヘッダ判定: "ご利用日" + "海外通貨利用金額"
三井住友 smbc_adapter.py スタブのみ CSV サンプル待ち。ヘッダ: "利用日" + "利用金額(円)" 想定
JCB jcb_adapter.py スタブのみ CSV サンプル待ち
楽天 rakuten_adapter.py スタブのみ CSV サンプル待ち

7-3. カード自動判定ロジック

  1. ファイル名に "amex" / "american" が含まれる → AMEX アダプタ
  2. ファイル名での判定不可 → CSV 先頭行のヘッダ列名を照合
  3. AMEX: ["ご利用日", "ご利用内容", "海外通貨利用金額"] が含まれる
  4. 判定できない場合 → _要確認/ に退避・通知

7-4. アダプタ共通インターフェース

class BaseCardAdapter(ABC):
    CARD_LABEL: str  # "AMEX" / "SMBC" / etc.

    @classmethod
    def can_handle(cls, headers: list[str]) -> bool:
        """CSVヘッダ行から対応可否を返す"""
        ...

    def parse(
        self,
        filepath: str,
        fiscal_year: int = 2026,  # 年度(MM/DD → YYYY-MM-DD 変換用)
    ) -> list[CardTransaction]:
        """CSV をパースして CardTransaction リストを返す"""
        ...

8. INBOX 提案(CEO 承認待ち)

CEO 判断ポイント:INBOX フォルダ作成の可否

現在の A10 Drive には法人クレカ CSV / PDF 専用の投入フォルダが存在しない。 以下の新規フォルダ作成を提案する。作成は CEO 承認後に実施。

8-1. 提案フォルダ

フォルダ名(案)用途親フォルダ
INBOX_creditcard CSV / PDF の投入口(すべてのカード共通) 経理 Drive ルート 1RbqJDW00aQGi9eqhaTdG_K0girAVHdkl

8-2. フォルダ内の流れ(承認後)

投入
CEO が CSV or PDF を INBOX_creditcard/ にドロップ(Drive/Telegram/Discord 共通)
CSV
うーぱんポーラー(LaunchAgent 日曜 23:30 or 手動)が検知 → パース → 証憑管理簿に追加 → _processed/<YYYY-MM>/ へ移動
PDF
Codex がリネーム → 1qmG4ACZ-5H9Qh3R0hzIMkmBNJjZzIDAI(法人クレカ明細(随時保管)フォルダ)へ移動

8-3. SUICA ポーラーとの比較

項目SUICA ポーラークレカ CSV(今回)
投入フォルダINBOX_suicaINBOX_creditcard(提案)
処理スケジュール1時間毎 LaunchAgent日曜 23:30 or 手動(頻度低)
対象ファイルCSV のみCSV + PDF
書込先SUICA 明細管理簿スプシ証憑管理簿スプシ

9. AMEX プロトタイプ

9-1. テストタブ

プロトタイプの書き込み先:証憑管理簿スプシ内に一時タブ _proto_creditcard を作成。 主シート「証憑管理簿」本体には書かない。

9-2. フィクスチャデータ(AMEX GRAB 18件)

今会話で確認した実データ(2026年5月 ベトナム GRAB 利用)を fixture として使用。

9-3. 整形後の出力(dry-run)

以下が証憑管理簿 14列フォーマットに変換した結果。

A 発生日 B 金額(JPY) C 外貨 D 店舗 E 支払区分 F 証憑種別 G 証憑形式 H Drive URL K 信頼 N 備考(抜粋)
2026-05-0147476,960 VNDGRAB会社支払電子証憑クレカ明細(PDF保管後)0.95AMEX / rate:0.006
2026-05-01736119,600 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-01769124,800 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0325040,560 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0333354,080 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0338662,400 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0347576,960 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-046510,400 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0410917,680 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0429046,800 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0440064,480 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0447876,960 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0456290,480 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0621134,320 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0622937,440 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-07579,360 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0729447,840 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006
2026-05-0743069,680 VNDGRAB会社支払電子証憑クレカ明細0.95AMEX / rate:0.006

合計 18 件。JPY 合計: 6,348 円。VND 合計: 1,030,720 VND

9-4. プロトタイプスクリプト

実装ファイル:2_Areas/A10_corporate_finance/phase_b_reimbursement/creditcard/amex_adapter.py

実行方法(CEO 承認後、テストタブへの書き込み時):

# dry-run モード(スプシへの書き込みなし・整形結果のみ出力)
python amex_adapter.py --csv 20260609_amex_grab_charges.csv --dry-run

# テストタブ書き込みモード(_proto_creditcard タブに書く・主タブは触らない)
python amex_adapter.py --csv 20260609_amex_grab_charges.csv --test-tab
今回の制約: 主シート「証憑管理簿」本体タブへの書き込みは CEO 承認後のみ。 プロトタイプは _proto_creditcard タブへの書き込み / dry-run 出力に限定。

10. CEO 判断ポイント

判断 1:INBOX_creditcard フォルダ作成の可否

Drive 経理ルート直下に INBOX_creditcard/ を新設する。 CSV・PDF 両対応の投入口として使う。
YES の場合:即時作成し drive_folder_ids.json を更新する。
NO の場合:手動パス指定でスクリプトを動かす運用も可能。

判断 2:テストタブへの書き込み実行の可否

証憑管理簿スプシに一時タブ _proto_creditcard を作成し、 AMEX fixture データ 18件を書き込んでよいか。
YES の場合:プロトタイプスクリプトを実行して実物を確認できる。
NO の場合:dry-run 出力(このHTML)で設計確認のみ。

判断 3:他カード(三井住友/JCB/楽天)の CSV サンプル提供

各カードのアダプタを実装するには CSV ヘッダ・サンプルデータが必要。 各カードの明細 CSV(個人情報マスク済みで可)を提供いただけるか。
提供可能なカードから順次アダプタを実装する。

判断 4:代表個人カード(将来)の支払区分ルール

現在は「法人カード = 会社支払」固定。
将来、代表個人カードの明細も同じパイプラインで扱う場合: カードごとに支払区分を設定ファイルで切り替える設計を用意する(例: card_config.json)。
確認:代表個人カード(立替扱い)の CSV 取込を今後のスコープに含めるか。

判断 5:実突合エンジン(Phase 2)の Go / No-Go

明細 side 登録が安定稼働してから突合エンジン実装に進む。 Phase 1 完了後に Go / No-Go を判断いただきたい。
突合エンジンの前提:GRAB レシート行(既存証憑)が証憑管理簿に正しく登録されていること。

11. 変更履歴

日付バージョン変更内容
2026-06-10v1.0初版作成(CEO 指示 2026-06-10 に基づく設計)