1. 基本情報

焦点質問: INV承認/STL消込時にどのような仕訳を自動生成するか?

項目内容
ファイル403_subledger_engine.js
主要関数processInvoiceApprovals (A) / processSettlementClearings (B)
役割サブ元帳のステータス遷移に応じて 42_trn_journal へ自動仕訳を生成
呼び出し元メニュー「⚙️ 定期RPA起票」配下(予定)

アーキテクチャ図

flowchart TB
    subgraph BUD["20s BUD — 予算・契約マスタ"]
        bud["20_bud_xxx"]
    end

    subgraph WRK["30s WRK — サブ元帳"]
        ORD["31_wrk_order (ORD)
発注・契約台帳"] INV["32_wrk_invoice (INV) ★SSOT
請求・債権債務台帳"] STL["33_wrk_bank (STL)
入出金・消込台帳"] end subgraph TRN["40s TRN — 総勘定元帳"] JNL["42_trn_journal (JNL)
仕訳台帳 — SSOT"] end bud -->|"RPA起票
401_bat_rpa.js"| INV bud -->|"RPA起票"| ORD INV -->|"Action A
費用計上仕訳"| JNL INV -.->|"STL自動作成"| STL STL -->|"Action B
決済仕訳"| JNL STL -->|"Action B: 残高更新"| INV INV <-->|"ORD残高減算"| ORD

ライフサイクル

flowchart LR
    A["ORD
発注済"] --> B["INV
未処理"] B --> C["INV
承認済"] C -->|"Action A"| D["TRN生成
+ ORD残高減算"] D --> E["STL
消込済"] E -->|"Action B"| F["TRN生成
+ INV残高=0
+ Action A TRN
決済日_実績更新"]

2. インターフェース定義

関数引数戻り値トリガー
processInvoiceApprovalsなしvoidメニュー手動実行
processSettlementClearingsなしvoidメニュー手動実行

Action A 入出力

シート読み書き役割
32_wrk_invoice (INV)oo対象行の検出 + 自動仕訳JNL_ID書き戻し + 即決済完了
31_wrk_order (ORD)oo発注残高の減算
42_trn_journal (TRN)ooTRN_ID発番 + 仕訳行追記
33_wrk_bank (STL)oSTL自動作成

Action B 入出力

シート読み書き役割
33_wrk_bank (STL)oo対象行の検出 + 自動仕訳JNL_ID書き戻し + 消込手段セット
32_wrk_invoice (INV)ooINV情報参照 + 未決済残高再計算 + ステータス更新
42_trn_journal (TRN)ooTRN_ID発番 + 仕訳行追記 + Action A TRN決済日_実績更新

3. データスキーマ

42_trn_journal (TRN_JOUR)

#ヘッダー名型/書式備考
1A取引IDTRN_YYYYMMDD_NNNNPK
2B発生日(P/L計上日)yyyy-mm-ddP/L計上日
3C決済日_計画yyyy-mm-ddINVの決済日_計画
4D決済日_実績yyyy-mm-ddAction Bで書き込み
5E収支区分支出/収入
6F取引先名
7G科目名
8H税区分
9I外貨金額#,##0将来の外貨対応用
10J通貨JPY等
11K税抜金額_実績#,##0
12L消費税額_実績#,##0
13M税込金額_実績#,##0
14N組織名
15OPJ
16P決済手段
17Q仕訳ステータス計上済/取消
18R証憑URL
19S摘要
20T管理IDINV_ID or STL_ID
21UCF支払IDレガシー
22VCF支払ID枝番レガシー
23W収支区分コードDatamart用
24X取引先コード
25Y法人番号
26Z主科目コード
27AA税区分コード
28AB組織コード
29ACPJコード
30AD決済手段コード
31AE仕訳ステータスコード

: ヘッダー名はコード上の buildTrnRow_ で使用される名称と一致。税抜金額_実績 / 消費税額_実績 / 税込金額_実績 / 仕訳ステータス はコード実装に基づく正式名称。


4. 処理ロジック

4.1 Action A — INV承認 → 費用計上仕訳

STEP 1〜2: 初期化

STEP処理入力出力条件
A1.1ヘッダーインデックス構築32/42/31/33タブ 1行目invIdx, trnIdx, ordIdx, bankIdx
A1.2ORDデータMap化31_wrk_order: 発注ID(ORD), 発注残高(自動計算), 税込金額_発注ordMap = { ordId: { rowIndex, balance } }残高未設定 → 税込金額_発注フォールバック
A1.3天引き額Map構築32_wrk_invoice: 仕訳振替INV全行deductMap = { ordId|YYYY-MM: 合計額 }有効フラグ=TRUE、決済手段="仕訳振替"、摘要に【RPA:HC】を含むもの
A1.4TRN_ID / STL_ID 発番キャッシュリセットバッチ先頭で初期化

経理向け補足: 「天引き額Map」は、給与支払い時に源泉税・住民税・社会保険料などを給与から差し引く(天引きする)金額の集計。仕訳振替INVの金額を合算し、STL(決済)の差引支給額算出に使用する。キーは ORD_ID|YYYY-MM(対象月は摘要の【RPA:HC】接頭辞の直後7文字から抽出)。

STEP 3: INVスキャン → TRN生成

STEP処理入力出力条件
A3.0有効フラグチェックINV.有効フラグFALSE → SKIP
A3.1スキップ判定①INV.請求ステータス≠ "承認済" → SKIP
A3.2スキップ判定②INV.自動仕訳JNL_ID≠ 空 → SKIP(転記済)
A3.3スキップ判定③INV.発生日(P/L計上日)空 → SKIP
A3.4TRN行生成INV全列42_trn_journal 新規行buildTrnRow_ でINV→TRNマッピング。仕訳ステータス="計上済"
A3.5JNL_ID書き戻しTRN_IDINV.自動仕訳JNL_ID
A3.6ORD残高減算INV.親発注ID(ORD), INV.税込金額_計画ORD.発注残高(自動計算)親ORDなし → スキップ

STEP 4〜5: STL自動作成 + 即決済完了

STEP処理入力出力条件
A4.1STL作成判定INV.決済手段, INV.摘要仕訳振替 → STL不要。資産計上 → STL不要(ただし摘要に"未収入金"含む → STL作成)
A4.2STL行生成INV情報33_wrk_bank 新規行決済口座=決済手段(資産計上例外時は"口座振込_福井銀行")。決済金額=abs(税込金額_計画) − deductMap差引き(給与INVのみ天引き適用)
A5.1即決済完了INV.決済手段INV.請求ステータス="決済完了", INV.未決済残高=0仕訳振替、または資産計上かつSTL不要のINV

STEP 6: 一括書き込み

STEP処理出力先
A6.1TRN一括追記42_trn_journal 末尾
A6.2STL一括追記33_wrk_bank 末尾(列Bで最終行判定)
A6.3INV JNL_ID一括書き戻し32_wrk_invoice.自動仕訳JNL_ID
A6.4ORD残高一括更新31_wrk_order.発注残高(自動計算)

INV → TRN 列マッピング (Action A)

全フィールドをヘッダー名ベース (buildTrnRow_) で設定。列番号のハードコードなし。

TRN列ソースINV列
取引ID自動発番
発生日(P/L計上日)発生日(P/L計上日)
決済日_計画← (空なら発生日)決済日_計画
決済日_実績空 (Action Bで更新)
収支区分収支区分
取引先名取引先名
科目名科目名
税区分税区分
外貨金額税抜金額_計画
通貨← (空なら'JPY')通貨
税抜金額_実績税抜金額_計画
消費税額_実績消費税額_計画
税込金額_実績税込金額_計画
組織名組織名
PJ名PJ名
決済手段決済手段
仕訳ステータス"計上済"
証憑URL証憑URL
摘要INV摘要 + " [INV:{請求ID}]"摘要, 請求ID(INV)
管理ID請求ID(INV)

ORD発注残高の減算

減算額 = INV の 税込金額_計画
ordBalUpdates[ordId] = ordMap[ordId].balance - 税込金額_計画
→ 31_wrk_order の 発注残高(自動計算) 列に書き戻し

4.2 Action B — STL消込 → 決済仕訳

STEP 1〜3: 初期化

STEP処理入力出力条件
B1.1ヘッダーインデックス構築32/33/42タブ 1行目invIdx, bankIdx, trnIdx
B1.2INVデータMap化32_wrk_invoice 全行invMap = { invId: { rowIndex, pjName, orgName, shushi, jnlId, ordId, settleYm } }有効フラグ=TRUEのみ
B1.3INV-ORD逆引きMap構築32_wrk_invoice 全行invOrdMap = { ordId: [rowIndex, ...] }仕訳振替INV決済完了用
B1.4TRNデータMap化42_trn_journal.取引IDtrnMap = { trnId: rowIndex }Action A TRNの決済日_実績更新用

STEP 4: STLスキャン → 決済仕訳生成

STEP処理入力出力条件
B4.1スキップ判定①STL.決済ステータス≠ "消込済" → SKIP
B4.2スキップ判定②STL.自動仕訳JNL_ID≠ 空 → SKIP(転記済)
B4.3スキップ判定③STL.消込対象請求ID(INV)空 → SKIP + warn
B4.4スキップ判定④invMapに消込対象INV未存在 → SKIP + warn
B4.5スキップ判定⑤STL.決済日_実績空 → SKIP
B4.6バリデーション: 未来日STL.決済日_実績 vs 本日決済日 > 本日 → SKIP + ダイアログ警告
B4.7バリデーション: 発生前決済STL.決済日_実績 vs INV.発生日前払いINV(決済日_計画<発生日)または収入INV → OK。それ以外で決済日<発生日 → SKIP + 警告
B4.8メイン決済仕訳生成STL.税込金額_決済42_trn_journal 新規行科目名="現金・預金", 税区分="対象外", 仕訳ステータス="計上済"
B4.9JNL_ID書き戻しTRN_IDSTL.自動仕訳JNL_ID
B4.10差額仕訳STL.差額(手数料等)42_trn_journal 新規行≠ 0 → 追加TRN行。科目=差額処理科目(空なら"支払手数料")
B4.11仕訳振替INV決済完了同ORD+同決済日_計画月の仕訳振替INVINV.未決済残高=0, INV.請求ステータス="決済完了"同一ORD内で決済手段="仕訳振替"かつ発生日月=決済日_計画月のINV
B4.12Action A TRN決済日更新INV.自動仕訳JNL_ID → trnMap検索TRN.決済日_実績=STLの決済日TRN未発見 → スキップ

経理向け補足: 「決済日 < INV発生日」は、費用の発生(計上)より前に代金を支払っている状態。前払費用(例: 年払いSaaSの一括支払い)や売上入金(入金が納品より先)の場合は会計上正当なため処理を続行する。それ以外のケースは入力誤りの可能性があるためスキップし、警告ダイアログを表示する。

STEP 5: INV未決済残高の再計算

STEP処理入力出力条件
B5.1消込済STL集計33_wrk_bank: 消込対象INV, 税込金額_決済settledByInv = { invId: totalSettled }消込済 かつ 自動仕訳JNL_IDあり(Action B処理済)のSTLのみ
B5.2未決済残高再計算INV.税込金額_計画, settledByInvINV.未決済残高(自動計算)残高 = abs(税込金額_計画) − settledByInv[invId]。1円未満切捨て。負額INVは符号を保持
B5.3ステータス更新未決済残高INV.請求ステータス=0 → "決済完了"、settled>0 かつ残高>0 → "部分決済"

STEP 6: 一括書き込み

STEP処理出力先
B6.1TRN一括追記42_trn_journal 末尾
B6.2STL JNL_ID更新 + 消込手段自動セット + ハイライトクリア33_wrk_bank.自動仕訳JNL_ID, 消込手段, 背景色
B6.3INV残高/ステータス更新32_wrk_invoice.未決済残高(自動計算), 請求ステータス
B6.4TRN決済日更新42_trn_journal.決済日_実績

: B6.2 では消込手段が空の場合に「手動」を自動セットし、緑ハイライト(#d9ead3)をクリアする。

STL → TRN 列マッピング (Action B: メイン決済仕訳)

TRN列ソースSTL列
取引ID自動発番
発生日(P/L計上日)決済日_実績
決済日_計画決済日_実績
決済日_実績決済日_実績
収支区分INVから取得 (フォールバック:"支出")
取引先名取引先名
科目名"現金・預金" (固定)
税区分"対象外" (固定)
外貨金額税込金額_決済
通貨"JPY" (固定)
税抜金額_実績税込金額_決済
消費税額_実績0
税込金額_実績税込金額_決済
組織名INVから取得
PJ名INVから取得
決済手段決済口座
仕訳ステータス"計上済"
摘要STL摘要 + " [STL:{決済ID} INV:{消込対象ID}]"摘要, 決済ID(STL), 消込対象請求ID(INV)
管理ID決済ID(STL)

STL → TRN 列マッピング (Action B: 差額仕訳)

TRN列
取引ID自動発番 (メインとは別のTRN_ID)
発生日(P/L計上日)決済日
決済日_実績決済日
収支区分"支出"
取引先名STLの取引先名
科目名STLの差額処理科目 (空なら "支払手数料")
税区分"対象外"
通貨"JPY"
税抜金額_実績STLの差額(手数料等)
消費税額_実績0
税込金額_実績STLの差額(手数料等)
組織名INVから取得
PJ名INVから取得
仕訳ステータス"計上済"
摘要"手数料等差額 [STL:{決済ID}]"
管理IDSTLの決済ID

5. 財務ロジック (FRD)

※ 本セクションは経理担当・CFOが検証可能な表現で記述。技術用語は使用しない。 → 技術詳細: §4 参照

5.1 費用計上時の仕訳パターン

請求書が承認されると、以下の仕訳パターンで費用計上仕訳を自動生成する。

業務イベント借方貸方タイミング備考
通常の費用計上(後払い)費用科目(請求書の科目)未払金(決済待ち)承認時STL消込まで未決済残高が残る
通常の費用計上(即払い)費用科目現金・預金承認時STL消込で最終決済
仕訳振替(天引き項目)預り金・社会保険料等給与(相殺)承認時(同時振替)STL不要。即時決済完了
資産計上(B/S即時)資産科目承認時STL不要(CF除外)。即時決済完了。ただし未収入金はSTL作成
収入計上現金・預金売上等の収入科目承認時収支区分="収入"

5.2 決済消込時の仕訳パターン

消込済の入出金レコードに対して、以下の仕訳パターンで決済仕訳を自動生成する。

業務イベント借方貸方タイミング備考
通常の決済(支出)未払金(消込)現金・預金消込時INV未決済残高を減算
通常の決済(収入)現金・預金未収入金(消込)消込時入金処理
振込手数料等の差額支払手数料(または指定科目)現金・預金消込時(同時)差額≠0の場合のみ追加仕訳を生成
部分決済未払金(一部消込)現金・預金消込時残高>0 → ステータス="部分決済"

5.3 天引き額の計算(給与支払い)

差引支給額 = 月額給与・報酬の請求総額 − 天引き合計(源泉税 + 住民税 + 社会保険料等)

  • 天引き対象: 同一発注+同一対象月の仕訳振替INV金額の合計
  • 対象月の判定: 摘要の「【RPA:HC】YYYY-MM」から抽出
  • STL自動作成時の決済金額として使用

5.4 未決済残高の再計算

未決済残高 = 請求総額(絶対値) − 全消込済STLの決済金額合計

  • 残高=0 → 「決済完了」
  • 残高>0 かつ一部消込済 → 「部分決済」
  • 減算方式ではなく、全STL合計から逆算して再計算する(整合性保証)
  • 集計条件: 消込済 かつ 自動仕訳JNL_IDあり(Action B処理済のSTLのみ)

5.5 バリデーションルール

チェック条件処理
未来日チェック決済日が本日より後処理をスキップし、ダイアログで警告を表示する
発生前決済チェック決済日 < INV 発生日前払い/収入は続行・他はスキップ + 警告ダイアログ

6. 冪等性・整合性保証

保証項目メカニズム検証方法
Action A 二重転記防止INV.自動仕訳JNL_IDが空の行のみ対象。転記後にJNL_IDを書き戻し同じ関数を2回実行 → 2回目は0件
Action B 二重転記防止STL.自動仕訳JNL_IDが空の行のみ対象。転記後にJNL_IDを書き戻し同じ関数を2回実行 → 2回目は0件
有効フラグチェック有効フラグ=FALSEの行は全処理でスキップA/B両方で初期スキャン時にチェック
TRN行の書き込み位置trnSheet.getLastRow() + 1 の直下に追記。行数不足時は insertRowsAfter で自動拡張
STL行の書き込み位置findTrueLastRow_ で列B(決済ID)の最終行を判定列Aのチェックボックス回避
TRN配列サイズtrnColCount をヘッダーから動的取得(現在31列)スキーマ変更時も自動追従
INV未決済残高の整合性減算方式ではなく、全消込済STLの合計から請求総額を逆算して再計算部分決済・再実行でも正しい残高を保証
同一行重複更新防止updatedRows オブジェクトで処理済行を追跡

7. テスト仕様

テストIDテスト名前提条件期待結果
T1Action A 基本INV: 請求ステータス=承認済, JNL_ID=空TRN 1行生成, INVにJNL_ID書き戻し
T2Action A 冪等性同じINVを2回実行2回目は0件 (JNL_ID既存のためスキップ)
T3Action A ORD残高減算INV: 親発注ID=ORD_xxx, 税込金額_計画=22,000ORD残高が22,000減算
T4Action A 発生日空INV: 発生日=空スキップ (TRN未生成)
T5Action A 複数INV同時3件の承認済INVTRN 3行生成, 各INVにJNL_ID書き戻し
T6Action A ORDなしINV: 親発注ID=空TRN生成OK, ORD残高減算はスキップ
T7Action A 税込金額_計画INV: 税抜20,000, 消費税2,000, 税込22,000TRN: 税抜金額_実績=20,000, 消費税額_実績=2,000, 税込金額_実績=22,000
T8Action B 基本STL: 消込済, JNL_ID=空, 対象INV存在TRN 1行生成(科目=現金・預金), INV残高=0
T9Action B 差額ありSTL: 差額=550, 差額処理科目=支払手数料TRN 2行生成(決済+手数料)
T10Action B 差額あり(科目空)STL: 差額=550, 差額処理科目=空差額TRNの科目="支払手数料"(フォールバック)
T11Action B 冪等性同じSTLを2回実行2回目は0件
T12Action B 対象INV未存在STL: 消込対象ID=存在しないINV_IDスキップ + console.warn
T13Action B 消込対象ID空STL: 消込対象請求ID=空スキップ + console.warn
T14Action B Action A TRN更新INVにJNL_ID=TRN_xxx ありTRN_xxx の決済日_実績が更新される
T15Action A→B 連続実行INV承認 → STL消込TRN 2行(費用計上+決済), ORD残高減算, INV残高=0

付録A: ヘルパー関数一覧

generateTrnId_

TRN_ID発番: "TRN_{yyyyMMdd}_{NNNN}" 形式
  - dateStr ごとにキャッシュし、既存TRN_IDの最大連番+1から発番
  - offset でバッチ内連番を加算
  - バッチ開始時に _cache をリセット

generateStlId_

STL_ID発番: "STL_{yyyyMMdd}_{NNNN}" 形式
  - generateTrnId_ と同じロジック
  - 33_wrk_bank の決済ID(STL)列から最大連番を取得

buildHeaderIndex_

ヘッダー配列からインデックスMapを構築: { ヘッダー名: インデックス }
全シートの列参照で使用。列順序の変更に強い。

buildTrnRow_

TRNヘッダーインデックスMap + fields (ヘッダー名→値) から TRN行配列を構築。
列番号のハードコードなしに TRN行を組み立てる。

付録B: メンテナンスツール

メニュー「⚙️ システム管理」から実行可能。

42_trn_journal の孤立TRN削除 (cleanupOrphanTrn)

孤立条件(いずれかに該当):
  (1) TRN_IDが 32/33 の自動仕訳JNL_ID にない
  (2) 管理IDが 32 の INV_ID にも 33 の STL_ID にも存在しない

動作:
  対象の取引ID一覧をダイアログに表示(20件超は省略)
  OK → 下の行から順に削除

31/32/33 タブの重複行チェック (cleanupDuplicateRows)

ID列(ORD_ID / INV_ID / STL_ID)で重複を検出。
最初の行を残し、重複行を赤色(#F4CCCC)でマーク。
解消後の再チェックで赤を自動リセット。

32/33 タブの整合性チェック (checkInvStlConsistency)

チェック1: 承認済/部分決済/決済完了(現金決済)のINVにSTLがない → 黄色マーク
チェック2: STLが参照するINVが32に存在しない → 黄色マーク
チェック3: 32/33のJNL_IDが42に存在しない(TRN欠落) → 青色マーク
解消後の再チェックで色を自動リセット。

付録C: ADR

実装方針: ヘッダー名ベース参照

全シート (INV, STL, ORD, TRN) の列参照を buildHeaderIndex_ + ヘッダー名で行う。 列番号のハードコードは一切使用しない。スキーマ変更時にコード修正が不要になる。

// 列参照
const invIdx = buildHeaderIndex_(invData[0]);
const status = row[invIdx['請求ステータス']];

// TRN行構築
const trnRow = buildTrnRow_(trnIdx, trnColCount, {
  '取引ID': trnId,
  '発生日(P/L計上日)': accrualDate,
  // ...
});

// 書き戻し
invSheet.getRange(rowNum, invIdx['自動仕訳JNL_ID'] + 1).setValue(trnId);