1. 概要

焦点質問: 領収書PDFからの自動読取と立替精算STL消込はどう動作するか?

背景・課題

立替精算の領収書・請求書は紙やPDFで届くため、手動で金額・取引先を転記しSTLと紐づける作業が煩雑だった。Gemini APIによるPDF自動解析と33_wrk_bankの立替精算STLとの自動マッチングにより、帳票との紐づけを半自動化する。

処理フロー(マトリクス)

項番処理フェーズ入力(論理名)入力(物理名: タブ.列)処理詳細 / 変換ロジック出力(論理名)出力(物理名: タブ.列)例外処理
S0.1Step 0: PDF読み込みGoogle Drive PDFDrive フォルダimportReceiptPdfs() — Gemini APIで解析→35タブに出力。処理済みPDFはprocessedに移動領収書データ35_wrk_receipt (新規行)⚠️ PDF解析失敗→スキップ+ログ
S1.1Step 1: マッチング確認領収書 × 立替STL35_wrk_receipt × 33_wrk_bankimportReceiptStatement() — 立替精算STLとマッチング。結果を35タブに表示(消込しない)処理結果, STL情報35_wrk_receipt.T〜Y列SKIP:金額なし
S1.2ユーザー確認35_wrk_receiptMATCHED行: 確認FLG=TRUE。UNMATCHED行: 手動STL_ID入力 or データ修正→再実行確認FLG35_wrk_receipt.S列
S2.1Step 2: 消込実行確認FLG=TRUE行35_wrk_receipt.S列applyReceiptSettlement() — 確認FLG=TRUE行を処理
S2.233タブ更新マッチSTL情報35_wrk_receipt.U列消込手段="帳票", 立替日=領収書の決済日_実績(決済ステータスは未処理のまま消込手段, 立替日33_wrk_bank.P,E列※1
S2.335タブ更新処理結果→消込済, 背景色=#D9EAD3(薄緑)処理結果35_wrk_receipt.T列
S2.4ユーザー手動消込33_wrk_bankユーザーが決済ステータスを"消込済"に変更、決済日_実績を入力ステータス, 決済日33_wrk_bank.G,F列
S3.1Step 3: Action B通常のAction Bで仕訳生成42_trn_journal

脚注:

  • ※1: 領収書消込はクレカ消込と異なり、決済ステータスを自動で消込済にしない。立替精算は実際の立替者への振込(別のタイミング)が必要なため

2. 設計判断

選択肢メリットデメリット選定
案A: OCR + ルールベース抽出決定的・OCR 精度高非定形対応にテンプレ別パーサー必要
案B: LLM (Gemini) で PDF 直接解析GAS 親和性・非定形対応・要件変更容易非決定性・コスト変動・レート制限採用

→ 詳細: ADR-0007 Gemini APIを領収書解析に使用する判断


3. 変更内容

3.1 スキーマ (35_wrk_receipt タブレイアウト)

データ列 (A〜R列)

#ヘッダー入力/自動説明制約
1A管理ID文字列自動RCP_0001, RCP_0002, ... (自動採番)RCP_NNNN形式
2B処理日時日時自動データ投入日時
3C証憑種別文字列自動領収書 / 請求書 (Gemini が自動判定)
4D取引先名文字列自動発行元の会社名
5E🏢住所文字列自動発行元住所 (市区町村まで)
6F税込金額_決済数値自動税込金額
7G税抜金額_決済数値自動税抜金額
8H消費税額_決済数値自動消費税
9I源泉税額数値自動源泉徴収
10JT番号文字列自動インボイス登録番号 (Tで始まる13桁)^T\d{13}$
11K帳票番号文字列自動請求書番号 / 領収書番号 / 注文番号
12L発行日日付自動帳票の発行日YYYY-MM-DD
13M発生日(P/L計上日)日付自動請求期間の終了日 (= P/L 計上日)YYYY-MM-DD
14N決済日_実績日付自動支払日YYYY-MM-DD
15O決済手段文字列自動クレジットカード等
16P摘要文字列自動商品名・サービス名 (50字以内)
17Qファイル名文字列自動元PDFのファイル名 (複数ページなら (pN) 付き)
18R証跡リンクURL自動Google Drive の PDF リンク

GAS管理列 (マッチ結果: S〜Y列)

#ヘッダー入力/自動説明
19S確認FLGBOOL入力ユーザーがマッチ結果を確認後にTRUEにする
20T処理結果文字列自動MATCHED / UNMATCHED / SKIP:金額なし / 消込済 / 未登録 / 26タブ登録済
21Uマッチ決済ID(STL)文字列自動マッチしたSTL_ID (UNMATCHEDの場合 候補:STL_XXXX)
22VSTL決済日_計画日付自動マッチSTLの決済日_計画
23WSTL税込金額_決済数値自動マッチSTLの税込金額
24XSTL取引先名文字列自動マッチSTLの取引先名
25YSTL摘要文字列自動マッチSTLの摘要

33_wrk_bank「立替日」列

33_wrk_bank の E列 (決済日の左隣) に「立替日」を追加。

項目説明
立替日社員がポケットマネーやカードで支払った日 (経費発生日)
決済日 (C/F実績日)会社が社員に精算金を振り込んだ日

receipt消込実行時に立替日をセット。決済日は会社精算時に手動入力。

3.2 ロジック

3.2.1 領収書PDF読み込み (Gemini API) — importReceiptPdfs()

スクリプトプロパティ:

キー
GEMINI_API_KEYGemini API キー
RECEIPT_FOLDER_ID領収書PDFを入れるDriveフォルダID (初回ダイアログで設定)

処理ロジック:

STEP処理入力出力条件
1PDFファイル取得Drive フォルダPDF配列DriveApp.getFilesByType(MimeType.PDF)
2PDF→base64→Gemini API送信各PDF構造化JSON配列モデル: gemini-2.5-flash、temperature=0.1、maxOutputTokens=8192
3JSON配列をページ単位で35タブに書き込みJSON配列35_wrk_receipt行1ページ=1レコード。空ページ(vendor・totalAmount共に空)はスキップ
4管理ID自動採番既存最大連番RCP_NNNN0パディング4桁
5証跡リンク付与file.getId()Drive URL
6処理済みPDFをprocessedサブフォルダに移動成功時のみ。失敗時は元フォルダに残る
7同一取引先の突合補正全レコード補正済みレコード後述

Geminiプロンプトの主要指示:

フィールド抽出ルール
docType領収書 or 請求書 (書類タイトルから判定)
invoiceNumber (T番号)Tで始まる13桁の登録番号のみ
docNumber (帳票番号)請求書番号/領収書番号/注文番号。INVで始まる番号はここ
accrualDate (発生日)請求期間の終了日。期間未記載なら発行日と同じ
複数ページページごとに1つのJSONオブジェクト。同一内容の重複は1つに統合。空白・目次ページはスキップ

JSON応答パース:

ケース処理
[...] 配列そのまま使用
{...} 単一オブジェクト[{...}] に配列ラップ
````json ... ` `` でラップ正規表現で [...] or {...} を抽出
不正な制御文字\n \r \t 以外の制御文字を除去
不完全なJSON (途中切断)未閉じの { [ を補完して再パース。途中のキー:値は切り捨て

後処理: 同一取引先の突合補正 (postProcessReceiptData_):

全PDF読み込み後、同一取引先名のレコードを多数決で補正:

  • T番号: 2件以上一致する値で少数派を上書き
  • 住所: 空欄を多数派の値で補完 (空欄→多数派値のみ。既存値は変更しない)

エラーハンドリング:

エラー条件処理ユーザー通知
503 (高負荷)最大3回リトライ (5秒間隔)
JSON解析失敗エラー詳細をダイアログに表示ダイアログ
失敗したPDF元フォルダに残る結果ダイアログにファイル名とエラー表示
大容量PDF (>100KB) で抽出1件ログ警告 (複数ページの可能性)ログのみ

3.2.2 マッチング確認 — importReceiptStatement()

マッチング対象 STL (33_wrk_bank):

#条件
1有効フラグ = TRUE
2決済口座が "立替精算" を含む
3決済ステータス = "未処理" のみ

マッチ成立条件 (全てAND):

#条件詳細
1金額一致receipt.税込金額_決済 が STL.税込金額_決済 の ±10%以内
2名前やや一致以下のいずれかを満たす(normalizeMerchant_ で正規化後に比較):
- receipt.取引先名 が STL.取引先名 に直接含まれる (or 逆)
- receipt.摘要 が STL.摘要 に直接含まれる (or 逆)
- トークン分割での部分一致 (2文字以上)

マッチング優先度 (同一金額・取引先の場合):

優先度条件スコア
1STL摘要に 発生日の年月 + 利用分 が含まれる+100
2日数差 ≤ 7日 (発生日 vs STL決済日_計画)+80
2日数差 ≤ 30日+60
2日数差 ≤ 60日+40
2日数差 ≤ 90日+20
3金額完全一致 (差分率=0)+50

同額・同取引先の月次SaaS で正しい月の STL を選ぶために、摘要の YYYY-MM利用分 と receipt の発生日年月を照合。

UNMATCHED時の候補表示:

マッチ不成立の場合、緩和条件で候補STLを提示する:

条件スコア
名前一致あり+50
金額差 ≤ 10%+30
金額差 ≤ 20%+15

候補がある場合: マッチ決済ID(STL)に 候補:STL_XXXX を表示。

行の背景色:

結果背景色
MATCHED#FFFFFF (白)
UNMATCHED#FCE5CD (薄橙)

スキップ条件 (マッチング確認):

条件結果
確認FLG = TRUEスキップ (確認済み行は一切触らない)
処理結果 = 消込済 or SKIPで始まるスキップ
税込金額_決済 = 0 or 空SKIP:金額なし

3.2.3 消込実行 — applyReceiptSettlement()

スキップ条件 (消込実行):

条件結果
処理結果 = 消込済スキップ
確認FLG ≠ TRUEスキップ
マッチ決済ID(STL) が STL_ で始まらないスキップ

33タブ更新 (STL_IDごとに合算):

同一STL_IDに対して複数の領収書がある場合、金額を合算して処理する。

項目更新内容
決済ステータス変更しない (未処理のまま)
消込手段帳票 をセット
立替日receipt の決済日_実績をセット (空の場合のみ)
税込金額_決済合算額と差額があれば補正
差額(手数料等)差額がある場合にセット
行の背景色#D9EAD3 (薄緑)

35タブ更新:

項目更新内容
処理結果消込済
STL情報列 (V〜Y)33タブの最新値で再更新
行の背景色#D9EAD3 (薄緑)

ユーザーが内容確認後に手動で「消込済」に変更 → Action B で仕訳作成

3.2.4 未登録領収書→26タブ登録 — transferReceiptToAdhoc()

35タブで処理結果=「未登録」の領収書を26_bud_adhocに費用登録する機能。

フィールドマッピング:

35タブ26タブ備考
-有効フラグ = TRUE固定
-管理ID = ADH_NNNN連番自動採番
発生日+摘要+取引先名取引名YYYYMMDD_摘要_取引先名
-取引先名単発_その他汎用ダミー固定
税抜金額_決済税抜金額_計画税抜が0の場合は税込金額を使用
消費税額_決済消費税額_計画
税込金額_決済税込金額_計画
-税区分対象外固定
発生日(P/L計上日)発生日(P/L計上日)そのまま
-収支区分支出固定
決済手段決済手段マッピング変換 (後述)
-決済ラグ(月)1固定
決済日_実績支払基準日DD(日)のみ
証跡リンク備考【領収書】RCP_NNNN + リンク

決済手段マッピング:

元の値 (部分一致)26タブの値
クレジット / クレカクレカ
振込 / 銀行口座振込
立替立替精算
その他立替精算 (デフォルト)

重複防止: 35タブの処理結果を「26タブ登録済」に更新 (背景色 #D9D2E9 薄紫)。再実行しても重複しない。

科目名・PJ名: 空欄のまま登録。ユーザーが26タブで後入力し、「📥 単発予算の自動起票」でINV生成。

3.3 UI (メニュー)

🔍 消込・マッチング
  ├─ 💳 クレカ明細マッチング確認
  ├─ 💳 クレカ消込実行 (確認FLG=TRUE)
  ├─ ───
  ├─ 📄 領収書PDFの読み込み (Drive)
  ├─ 🧾 領収書マッチング確認
  └─ 🧾 領収書消込実行 (確認FLG=TRUE)

📝 費用登録
  └─ 📥 未登録領収書→26タブ登録

4. 影響範囲

影響対象影響内容対応
502_receipt_reader.js領収書 PDF 読込(Gemini API)新規作成
501_cc_importer.js領収書マッチング・消込 + 26 タブ登録関数追加
002_constants.jsCC_MERCHANT_MAP 名寄せ辞書辞書エントリ追加
101_sys_config.jsメニュー登録 + 33 タブスキーマ拡張DDL 変更
403_subledger_engine.jsSTL 作成時の列対応 + Action B 連携既存拡張
33_wrk_bankE 列「立替日」+ P 列「消込手段」に 帳票スキーマ変更
35_wrk_receipt新規タブ(A〜Y 列)新規作成

§4 詳細関数: 502 = importReceiptPdfs / callGeminiForReceipt_ / postProcessReceiptData_、501 = importReceiptStatement / applyReceiptSettlement / transferReceiptToAdhoc


5. テスト仕様

テストIDテスト名前提条件期待結果
RCP-T01PDF読み込み正常系フォルダに1枚のPDFあり35タブに1行追加。RCP_NNNN採番。処理済みPDFがprocessedフォルダに移動
RCP-T02複数ページPDF3ページのPDF35タブに3行追加。ファイル名に (p1) (p2) (p3) が付与
RCP-T03PDF解析失敗画像のみPDF (テキスト抽出不可)エラーダイアログに失敗ファイル名が表示。PDFは元フォルダに残る
RCP-T04同一取引先の突合補正同一取引先の領収書3枚 (T番号が2枚一致・1枚不一致)不一致の1枚のT番号が多数派に補正される
RCP-T05マッチング正常系金額一致・取引先名一致のSTLが存在処理結果=MATCHED。STL情報が表示。背景白
RCP-T06マッチング金額範囲金額差がちょうど10%のSTLマッチ成立 (±10%以内)
RCP-T07マッチング金額超過金額差が11%のSTLマッチ不成立 (UNMATCHED)
RCP-T08UNMATCHED候補表示名前一致・金額差15%のSTLUNMATCHED。マッチ決済IDに 候補:STL_XXXX が表示
RCP-T09SaaS月次マッチング同額・同取引先のSTLが3件。うち1件の摘要にreceipt発生日の YYYY-MM利用分 あり摘要一致のSTLが最優先でマッチ
RCP-T10消込実行正常系確認FLG=TRUE、STL_IDあり33タブ: 消込手段=帳票、立替日セット。35タブ: 処理結果=消込済、背景薄緑
RCP-T11消込で決済ステータス不変消込実行後の33タブ決済ステータスが「未処理」のまま変化しない
RCP-T12消込金額差額補正receipt金額とSTL金額に差額あり33タブ: 税込金額_決済が補正、差額(手数料等)にセット
RCP-T13同一STLへの複数領収書合算確認FLG=TRUEの2行が同じSTL_IDに紐づく33タブ: 税込金額_決済が合算額に更新
RCP-T14スキップ: 確認FLG=TRUE再実行マッチング確認を再実行確認FLG=TRUE行はスキップされ上書きされない
RCP-T15未登録→26タブ登録処理結果=「未登録」の行あり26タブにADH_NNNN行が追加。35タブの処理結果=「26タブ登録済」。背景薄紫
RCP-T1626タブ登録の重複防止処理結果=「26タブ登録済」で再実行対象なしダイアログ。重複行は作成されない
RCP-T17決済手段マッピング決済手段=「クレジットカード」の領収書26タブの決済手段=「クレカ」

付録

付録A: 改修ファイル一覧

ファイル主要関数内容
502_receipt_reader.jsimportReceiptPdfs 等 3 関数領収書 PDF 読込(Gemini API)
501_cc_importer.jsimportReceiptStatement 等 3 関数領収書マッチング・消込 + 26 タブ登録
002_constants.jsCC_MERCHANT_MAP名寄せ辞書
101_sys_config.jsメニュー + 33 タブスキーマ拡張
403_subledger_engine.jsSTL 作成時の列対応 + Action B 連携

付録B: ADR