概要

項目内容
案件IDMAS-018
案件名財務3表の完全連動モデリング
カテゴリ新機能(FP&A)
PhaseP2
優先度★★
対象ファイル(主)100_config/101_sys_config.js42_trn_journal DDL 拡張)
400_domain/403_rpa_capex.js(既存拡張 or 新規補助関数)
対象ファイル(関連)600_report/601_datamart_ingest.js(集計フィルタ修正の要否を確認)
400_domain/407_rpa_orchestrator.js(公開API紐付け)
000_infra/003_contracts.js(JournalEntryDTO コメント更新の要否)
前提案件なし
人間検討事項(TODO_future.md 起票時)連動させるインプット項目の優先順位

TODO_future.md の定義(抜粋):

設備投資等のインプットが P/LB/S、C/F すべてに自動かつ瞬時に波及する仕組み。

経営の健全性・一貫性の担保。

目的

CAPEX(設備投資・借入)を代表的な入力とし、1 レコードの入力が P/L(減価償却費・支払利息)、B/S(固定資産・借入残高)、C/F(元金返済・投資キャッシュアウト)の 3 表すべてに矛盾なく反映される仕組みを整える。人間の介入を最小化しつつ、AI/自動生成結果は必ずレビュー承認してから財務諸表に反映させる Human-in-the-Loop パターンを適用する。

現在のコード

Phase 1-D 調査結果(400_domain/403_rpa_capex.js):

  • generateCapexInvoices(targetOverride, _silent) (403_rpa_capex.js:10) が既に実装済み。
    • 対象シート: 24_bud_capex_loan24_bud_capex ではなく _loan サフィックス付き。101_sys_config.js:775BUD_CAPEX キーに紐付け)
    • 固定資産計上(L165 assetMemo)、借入計上(L180 loanMemo)、頭金(L196 downMemo)・頭金返済(L238)、減価償却(L261 ループ・L268 depMemoP / L284 depMemoB)、元金返済(L335 repayMemo)・支払利息(L350 interestMemo)の仕訳生成が既に実装されている。
    • 生成先: 32_wrk_invoice(直接 42_trn_journal ではない)。INVAction A42_trn_journal 起票、STL 消込Action B → 決済仕訳追記という既存の Action A/B パイプラインで 3 表に波及する。
    • 冪等性摘要文字列の完全一致isDuplicate_(invData, invHeaders, memo) L166 等)で担保。【RPA:CAPEX】<YM> <資産名> <イベント> の接頭辞+一意キーで重複生成を防止。
  • RPAService.generateCapex(targetOverride, silent) (407_rpa_orchestrator.js:19) が公開 API として generateCapexInvoices に委譲。メニュー経由 / generateAll() (407_rpa_orchestrator.js:47) から呼ばれる。

本案件が新規追加する処理:

  1. 42_trn_journal DDL に 参照元種別 / 参照元ID カラムを追加(既存 WRK_ORDR に同名列あり 101_sys_config.js:846。命名を揃える)。
  2. 仕訳ステータス の既存値("自動計上" | "手動" | "仕訳振替")に "自動計上案" を追加し、Human-in-the-Loop の承認待ち状態を表現する。
  3. 403_rpa_capex.js の仕訳生成で、INV 起票経路を残しつつ生成された INV 行の追跡参照元種別='CAPEX' / 参照元ID=capMgrId でマーキングする(既に 参照元区分/参照元IDWRK_ORDR に埋められている L123-124 のパターンを INV にも拡張)。
  4. 集計対象の再定義(601_datamart_ingest.js): 現状は 32_wrk_invoice の「承認済 / 部分決済 / 決済完了」ステータスで取込む(L53)。請求ステータス='未処理' を除外しているため承認フローは既に存在する。MAS-018 では新規 CAPEX 生成 INV は 請求ステータス='未処理' で登録済みであり、人間が「承認済」に変更することで自動反映される仕組みが既に効いている。そこで MAS-018 スコープでは (A) 42_trn_journal の参照元メタデータ追加(B) ダッシュボード上での「未承認 CAPEX 件数」可視化に絞る設計とする(集計フィルタ変更は不要になる可能性あり=実装前要確認)。

修正方針

全体アーキテクチャ

CAPEX のインプット(24_bud_capex_loan の 1 レコード)を起点に、以下 3 群の仕訳が既存パイプライン経由で生成される構造を監査可能にする:

  1. 固定資産計上(B/S): 取得価額 ÷ 取引発生月
  2. 減価償却(P/L + B/S): 月次 = 取得価額 ÷ 償却月数(定額法)
  3. 借入返済(B/S + P/L + C/F): 月次 = 月額返済額(元本・B/S) + 月額支払利息(P/L)

既存 generateCapexInvoices の出力 INV 行すべてに下記を付与して追跡可能にする:

  • 参照元種別='CAPEX' — 生成元ドメインの識別
  • 参照元ID=<capMgrId>24_bud_capex_loan管理ID 列値(プレフィックス CPX_

計上月の計算

Utils.addMonths(ymStr, months) (004_utils.js:127) を使用する。引数は "YYYY-MM" 文字列Date オブジェクトは不可)。返り値も "YYYY-MM" 文字列。年度またぎ(例: "2025-10" + 6 → "2026-04")で自動的に年が繰り上がる。

冪等性ガード(DDL 変更を伴う)

  • 101_sys_config.js:860TRN_JOUR DDL headers 配列に 参照元種別 / 参照元ID を末尾追加(既存 31 列 → 33 列)。
  • 仕訳生成ロジックは 既存の isDuplicate_(invData, invHeaders, memo) による摘要一致判定を維持しつつ、追加でJournalRepository.findAll() の結果から 参照元ID が一致する仕訳を検索し、存在する場合は Utils.logInfo('generateCapexInvoices', '[skip] 既存仕訳あり: ' + capMgrId) でスキップする二段防御を採用する。
  • JournalRepository.append(dtos) (202_repository.js:291) が引数として JournalEntryDTO[] を受ける。ヘッダー位置合わせは appendDtosToSheet_ 側で行う。

Human-in-the-Loop(承認フロー)

  • 101_sys_config.js42_trn_journal DDL における 仕訳ステータス 選択肢に '自動計上案' を追加(既存値 "自動計上" | "手動" | "仕訳振替" は変更しない)。
  • 暫定方針: 既存 INV パイプラインの 請求ステータス='未処理' が実質的な「承認待ち」として機能しているため、仕訳ステータスの新規値追加は 42_trn_journal将来直接書き込む処理が出現したときのために予約的に行う。本案件では INV 側のステータスライフサイクルを主系統として使用し、仕訳ステータス='自動計上案' は将来拡張のためのハンドルとする。
  • 601_datamart_ingest.js の集計フィルタに 仕訳ステータス !== '自動計上案' を追加することは現状ソース(32_wrk_invoice + 33_wrk_bank)では不要(601 は 42_trn_journal を読まない 601_datamart_ingest.js:6 参照)。ただし将来 42_trn_journal を集計ソースに追加する際の準備として 自動計上案 選択肢の追加のみ先行する。
  • ユーザーが手動で INV の 請求ステータス を「承認済」に変更 → Action A による 42_trn_journal 起票 → マート再更新で財務諸表に反映、という既存フローを踏襲。

排他制御

LockService.getScriptLock() で処理全体を排他ロック(generateCapexInvoices に現状ロック呼び出しがないため、MAS-018 実装時に冒頭に追加する)。タイムアウトは 30 秒で tryLock(30000)。取得失敗時は Utils.logInfo でスキップログを出力して即終了。

影響範囲

ファイル変更量既存処理への影響
100_config/101_sys_config.jsTRN_JOUR DDL headers に 2 列追記(L860 付近)+ 仕訳ステータス 選択肢マスタへの値追加(該当 setVali 呼び出し箇所)setupAllSchemas 再実行で既存シートに 2 列追加される。既存行の値は空文字。後方互換あり
400_domain/403_rpa_capex.jsbuildInvRow_ 呼び出し箇所に '参照元種別': 'CAPEX''参照元ID': capMgrId を追加(7-8 箇所)。冒頭に LockService 取得を追加既存メソッド名・既存摘要文字列・既存 INV 列構成は変更しない。既存の isDuplicate_ 冪等性チェックは維持
400_domain/407_rpa_orchestrator.js変更なし(RPAService.generateCapex が既に公開 API として機能)
600_report/601_datamart_ingest.js変更なし(42_trn_journal を集計ソースとしていないため)

注意事項

  • 既存メソッドを変更・削除しない: generateCapexInvoices 本体のアルゴリズム(償却・返済の月次ループ、頭金分割、決済ラグ、返済日休日調整)は現状のまま維持する。Phase 1-D 調査で既に完全実装が確認されているため、MAS-018 で追加するのは「参照元メタデータの付与」と「DDL 拡張」のみ。
  • Utils.addMonths の第1引数は "YYYY-MM" 文字列Date オブジェクトを渡すと split('-') が失敗する(失敗パターン #17 関連)。既存コード(L223, L228, L262 等)もこの契約を守っている。
  • 計画変更時の非自動更新: 元データ(24_bud_capex_loan)が変更されても既存仕訳は自動更新しない。修正はユーザー側で既存 INV を無効化してから再起票を行う運用前提(本案件スコープ外)。
  • 科目マスタ未登録の科目名: AccountRepository.findAsMap() (202_repository.js:323) の返り値が undefined の場合、エラーを握りつぶさずスキップ+ Utils.logInfo でログ出力する。CLAUDE.md の「科目マスタ未登録はエラー、キーワード推測禁止」規約に従う。
  • 列参照はヘッダー名ベースindexOf / Contracts.* の行⇔オブジェクト変換)。列番号ハードコード禁止(CLAUDE.md コーディング規約)。
  • 実シート名の正規化: 24_bud_capex ではなく 24_bud_capex_loanUtils.getSheetByKey('BUD_CAPEX', '24_bud_capex_loan') で取得する(403_rpa_capex.js:18 の既存パターンに合わせる)。
  • CF シート名: Phase 1-E 調査の結果、実シート名は 81_cf_indirect / 81b_cf_indirect_ytd / 83_cf_daily / 84_cf_daily_plan101_sys_config.js:801-805 参照)。Gemini 調査資料にあった 81_cf_indirect_monthly実在しない
  • 42_trn_journal は監査証跡: 601_datamart_ingest.js:6 のコメントで明記されている通り「42_trn_journal は監査証跡として保持(集計ソースとしては使用しない)」。財務諸表マートは 32_wrk_invoice + 33_wrk_bank から生成される。この前提を崩さない。

エッジケース

条件動作理由
償却月数=0 または nullエラーログ出力・減価償却イベントの仕訳生成をスキップ0 ÷ 0 のゼロ除算防止。既存 L257 の if (acquireCost > 0 && depMonths > 0 && assetAccount) ガードが該当
借入金額=0 かつ 月額返済額=0借入計上・借入返済イベントの仕訳生成をスキップ不要仕訳の混入防止。既存 L181 / L308 の条件分岐が該当
会社支払開始年月 が未入力返済ループをスキップ(固定資産計上・減価償却は実行)既存 L308 `if (payStartYm && (monthlyRepay > 0
年度またぎの計上月Utils.addMonths("2025-10", 6) → "2026-04" が正しく生成される既存実装の月次ループ(L262 の減価償却、L364 の返済)で年またぎ処理がテスト対象
科目マスタ未登録の科目名AccountRepository.findAsMap()[accName]undefined → 当該仕訳をスキップ+Utils.logInfo('generateCapexInvoices', '[skip] 科目マスタ未登録: ' + accName) ログ出力CLAUDE.md 規約(キーワード推測自動分類禁止)
重複実行(同一 CPX_XXXX を再実行)一次ガード: 既存 isDuplicate_(invData, invHeaders, memo) が摘要完全一致で INV 重複を防ぐ。二次ガード: 本案件で追加する JournalRepository.findAll()参照元ID 検索によるスキップ+ログ冪等性保証(失敗パターン #16「合算マッチで同じ STL が再利用された」の matched=true ロックパターンを参考)
参照元ID が空文字(管理ID 未入力の CAPEX レコード)参照元種別='CAPEX' のみ付与し、参照元ID='' で登録(二次ガードはスキップ対象外)ID 欠落は運用ミス。INV 側 isDuplicate_ の一次ガードに依存。マスタ登録時に 管理ID 必須化は運用で担保
仕訳ステータス='自動計上案' のまま 42_trn_journal に直接書き込まれた仕訳(将来)財務諸表マートには反映されない(601 は 32_wrk_invoice + 33_wrk_bank 由来のみ集計)将来 42_trn_journal を集計ソースに追加した際の !== '自動計上案' 除外フィルタを実装できるよう、本案件で選択肢だけ先行追加
頭金 > 0 かつ 頭金分割回数=0既存 L212 `parseInt(... , 10)
返済月数=0 かつ 月額返済額>0repayEndYm=''(L306)→ 無限ループとなる危険。本案件で安全弁追加を推奨既存コードで明示的な 0 チェックが弱い。MAS-018 で if (repayMonths <= 0) continue; を返済ループ直前に追加することを検討

実データ検証

Phase 1 調査で判明した、実装前に必ず現物確認が必要な差分:

項目Gemini/仕様書前提Phase 1 調査結果(実際)対応方針
対象シート名24_bud_capex24_bud_capex_loan (101_sys_config.js:775, 403_rpa_capex.js:18)実装は _loan サフィックス付きで実装。Constants.SHEET_DEFAULTS では pattern: '24_bud_capex' と前方一致マッチで動作(002_constants.js:75
列名(償却期間)耐用年数償却月数101_sys_config.js:862仕様書・実装ともに 償却月数 を使用
列名(返済期間)返済期間返済月数101_sys_config.js:862仕様書・実装ともに 返済月数 を使用
CF 計算書シート81_cf_indirect_monthly81_cf_indirect101_sys_config.js:801実装時は Utils.getSheetByKey('CF_IND_ACT', '81_cf_indirect') を使用
集計ソース42_trn_journal32_wrk_invoice + 33_wrk_bank601_datamart_ingest.js:6MAS-018 では 42_trn_journal は監査証跡として保持。集計フィルタ変更は見送り、DDL 拡張と参照元メタデータ付与に絞る
既存 CAPEX 仕訳生成未実装前提generateCapexInvoices で既に完全実装済み(資産計上・減価償却・元金返済・支払利息・頭金分割・決済ラグ)MAS-018 は既存実装の追跡可能性向上が本質。ゼロから書き直さない
参照元種別 カラム命名WRK_ORDR には既に 参照元区分(区分) / 参照元ID が存在(101_sys_config.js:846命名の揺れ: INV/ORD 側は 参照元区分 だが JournalEntryDTO では仕様書通り 参照元種別 で統一するか、既存 参照元区分 に合わせるかを実装前に決定(推奨は 参照元区分 に統一、コードベース一貫性優先)

24_bud_capex_loan 実シートのヘッダーは 101_sys_config.js:862 の DDL 定義が唯一の真実:

["有効フラグ","管理ID","発生日(P/L計上日)","資産・契約名","取引先名","資産科目","取得価額","償却月数","負債科目","借入金額","返済月数","月額返済額","初回返済額","月額支払利息","頭金分割回数","決済ラグ(月)","返済日","休日調整","会社支払開始年月","決済手段","組織名","起票ターゲット月","最終起票年月日","備考"]

実装開始時に setupAllSchemas 実行済み dev 環境の実シートを開き、ヘッダー行と DDL 定義の完全一致を目視確認すること。

関連ドキュメント

仕様書リンク関連箇所
dev_mas-010_financial_modeling.mdMAS-010 が本機能の連動エンジンを共通利用する(下記 §補強 参照)。5 カ年月次予測での B/S・CF 推計を MAS-018 に委譲
dev_mas-013_investment_simulation.mdMAS-013 の CF 算出(税引後 CF・減価償却費の P/L-B/S-CF 整合)を MAS-018 連動エンジンに委譲予定
dev_mas-076_idempotency_fix.md冪等性実装パターン(既存仕訳の存在確認)
failure_patterns.md#16(合算マッチでの再利用)・#17(Date 文字列ソート)・#21-#24(数式設計の落とし穴)
000_infra/002_constants.jsSHEET_DEFAULTS24_bud_capex 前方一致の既定値)・ID_PREFIX_MAPCPX_ プレフィックス)
000_infra/003_contracts.jsJournalEntryDTO(仕訳フィールド一覧・仕訳ステータス 既存値)
400_domain/403_rpa_capex.jsgenerateCapexInvoices(既存の 3 イベント仕訳生成ロジック)
200_data/202_repository.jsJournalRepository.append / AccountRepository.findAsMap
600_report/601_datamart_ingest.js集計ソース定義(42_trn_journal は監査のみ)

補強: 在庫運転資本連動 + MAS-010 / MAS-013 共通エンジン化(2026-04-22 追記)

本案件の初版は CAPEX(設備投資・借入) 1 ドメインの 3 表連動に焦点を絞ったが、MAS-010(5 カ年財務モデリング)と MAS-013(投資回収シミュレーション)の双方が B/S・CF 予測の計算エンジンを必要としており、共通化した連動エンジン の切り出しを後続 Phase で実装する。

(A) 運転資本の連動(在庫・売掛金・買掛金)

CAPEX 以外にも 運転資本の変動 が 3 表に波及する主要経路として存在する。以下 3 項目を追加連動:

入力P/LB/SCF
在庫増(直接影響なし)棚卸資産 増運転資本増 → 営業 CF 減
売掛金増売上計上時に認識売掛金 増運転資本増 → 営業 CF 減
買掛金増仕入計上時に認識買掛金 増運転資本減 → 営業 CF 増

実装方針:

  • 400_domain/403_rpa_capex.js から機能拡張し 400_domain/404_rpa_working_capital.js を新設する派生案件として別起票(F-18b 候補)
  • 本仕様書ではインターフェース契約のみ定義し、実装は F-18b で行う
  • 在庫・売掛金・買掛金の計画値は 23_bud_subscription / 26_bud_adhoc 等の既存予算タブから取得 or 専用の 28_bud_working_capital タブを新設(設計判断は F-18b で決定)

(B) MAS-010 / MAS-013 共通エンジン: F18LinkageService

3 表連動の計算ロジックを公開サービスとして切り出し、MAS-010 と MAS-013 から共通利用する。

公開 API(計算エンジンのみ、仕訳書込は行わない):

/**
 * 入力: 月次 P/L 予測配列 + 前月 B/S スナップショット + パラメータ
 * 出力: 月次 B/S・CF 予測(F-10 / F-13 で共通利用)
 *
 * @param {Array<{年月, 科目名, 値}>} plRows - F-10 / F-13 の P/L 予測
 * @param {Object} prevBsSnapshot - 前月末 B/S 残高 { 現金, 売掛金, 在庫, 固定資産, 借入金, 純資産, ... }
 * @param {Object} paramsMap - { 減価償却年数, 借入金利, 元金返済額/月, 在庫回転日数, 売掛金回転日数, 買掛金回転日数 }
 * @returns {{ bsRows: Array, cfRows: Array, nextBsSnapshot: Object }}
 */
F18LinkageService.computeBsCfLinkage = function(plRows, prevBsSnapshot, paramsMap) { ... }

実装内容:

  • 減価償却費: P/L 費用計上 + B/S 固定資産減 + CF 非現金費用調整(営業 CF に加算)
  • 借入元金返済: B/S 借入金減 + CF 財務 CF 減
  • 支払利息: P/L 費用計上 + CF は営業 CF 内(間接法)
  • 運転資本変動: (売掛金増 + 在庫増) - 買掛金増 → CF 営業 CF 減
  • 現金残高: 前月現金 + 営業 CF + 投資 CF + 財務 CF

呼出側の責務:

  • MAS-010: 5 カ年月次 P/L 予測を plRows に渡し、月次 B/S・CF 予測を取得して 94_fs_longterm_forecast に書込
  • MAS-013: 投資案件の年次 P/L を plRows に渡し、税引後 CF を取得して NPV/IRR 計算に使用

実装工数見積: 本補強部分(B/S・CF 推計ロジック + API 切出)で追加 +8-12h。MAS-010 の Step 3「B/S・CF 推計」と合わせて実装する形を想定。

(C) 段階移行方針

  1. Phase 1(現状): CAPEX 1 ドメインの 3 表連動のみ。本仕様書の既存 §修正方針 で完結
  2. Phase 2(MAS-010 着手時): F18LinkageService.computeBsCfLinkage() を切り出し、MAS-010 が呼び出す形に整理。MAS-013 の CF 算出も本 API に委譲
  3. Phase 3(F-18b 別案件): 在庫・売掛金・買掛金の運転資本連動を追加。404_rpa_working_capital.js を新設

各フェーズの完了条件は別途 TODO_future.md で追跡(F-18b 新規起票は次回の TODO 整理時に検討)。

人間が検討すべき事項

  1. TODO_future.md 起票時の検討事項: 「連動させるインプット項目の優先順位」。

    • CAPEX(24_bud_capex_loan)は既に連動済み。次に連動させるべきは HC(22_bud_headcount)SaaS(23_bud_subscription)Pipeline(21_bud_pipeline)Adhoc(26_bud_adhoc) のいずれか。本案件 MAS-018 の実装範囲は CAPEX のメタデータ追加に留め、他ドメインへの展開は別案件化を推奨。
  2. CF 計算書の精度向上: 間接法 CF(81_cf_indirect)は現状 602_datamart_main.js:195 で生成される。CAPEX の投資 CF(固定資産取得)・**財務 CF(借入/元金返済)**を自動区分するため、11_mst_accountCF区分 カラム(値: '営業CF' / '投資CF' / '財務CF' / '非資金項目')を追加するか検討。本案件に含めるか将来案件とするか判断を要する。

  3. 命名規約の統一: WRK_ORDR参照元区分 / 参照元ID101_sys_config.js:846)、本案件で追加する 42_trn_journal は仕様書通り 参照元種別 / 参照元ID にするか、既存に合わせて 参照元区分 にするかの決定。推奨はコードベース一貫性優先で 参照元区分 に統一。ただし採用時は本仕様書・実装プロンプトの文言も合わせて修正すること。

  4. 計画変更時の自動再生成: 元データ(24_bud_capex_loan)が変更されたときに既存仕訳を差し替える機能は本案件スコープ外。参照元ID で既存 INV / 仕訳を特定し、論理削除(有効フラグ=FALSE)してから再生成するロジックを将来案件として検討。

  5. '自動計上案' ステータスの運用: 本案件では選択肢追加のみ先行する方針としたが、実際の運用フロー(誰がいつ承認するか、承認 UI の要否、一括承認機能)は未定義。運用設計が固まってから 601_datamart_ingest.js の集計フィルタに組み込むこと。

  6. 実装範囲の再確認: Phase 1-D 調査により「既存コードが既に大部分を実装済み」と判明したため、MAS-018 の実質スコープは

    • (A) 42_trn_journal DDL に 参照元種別/参照元ID 追加
    • (B) 既存 generateCapexInvoices の INV 行に 参照元種別/参照元ID を付与
    • (C) 仕訳ステータス 選択肢に '自動計上案' 追加(予約的)
    • (D) LockService による排他ロック追加

    となる。本案件の工数は当初想定よりも小さい。代わりに「他ドメインへの横展開(HC/SaaS 等)」を F-18b として別案件化することを推奨。

  7. 管理ID 必須化: 参照元ID の冪等性ガードが機能するためには、24_bud_capex_loan管理ID 列(CPX_NNNN 形式)が全レコードで必須入力である必要がある。現状は Constants.ID_PREFIX_MAP による自動採番に依存(002_constants.js:102)。採番タイミングと必須バリデーションの整合を確認すること。

実装プロンプト(Claude Code 用)

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-018「財務3表の完全連動モデリング」を実装してください。

## 実行前タスク

以下を Read で確認してから実装を開始する(Grep は発見のみ。固有名詞はすべて Read で裏取り):

- `000_infra/003_contracts.js`: JournalEntryDTO の全フィールド名。特に `仕訳ステータス` の既存値 `"自動計上" | "手動" | "仕訳振替"` を確認
- `100_config/101_sys_config.js` L860 付近: `TRN_JOUR` DDL の `headers` 配列(末尾に 2 列追記する箇所)・`仕訳ステータス` 選択肢マスタ `setVali` の該当行
- `400_domain/403_rpa_capex.js` 全体: 既存 `generateCapexInvoices` の実装範囲(資産計上 L165, 借入 L180, 頭金 L196, 頭金返済 L210-253, 減価償却 L261-302, 元金返済 L335, 支払利息 L350)。**上書き禁止箇所**を確実に把握
- `400_domain/407_rpa_orchestrator.js` L19: `RPAService.generateCapex` の委譲先(変更不要)
- `600_report/601_datamart_ingest.js` L6: 「42_trn_journal は監査証跡として保持(集計ソースとしては使用しない)」のコメント。**このファイルの変更は不要**
- `000_infra/004_utils.js` L127: `addMonths(ymStr, months)` の引数型(`"YYYY-MM"` 文字列)
- `200_data/202_repository.js` L259-298: `JournalRepository.findAll()` / `append(dtos)` のシグネチャ
- `24_bud_capex_loan` 実シートのヘッダー一覧(MCP または `SpreadsheetApp` で取得。DDL 定義 L862 と完全一致することを確認)

## 修正対象ファイル

- `100_config/101_sys_config.js`:
  - `TRN_JOUR` DDL の `headers` 配列末尾に `"参照元種別", "参照元ID"` を追記(※本案件内で仕様書 Human Review セクションと照合し、`参照元区分` に揃える案が採用された場合はそちらに合わせる)
  - `仕訳ステータス` の選択肢マスタ(MST_DICT 経由)に `'自動計上案'` を追加。既存値 `"自動計上" | "手動" | "仕訳振替"` は変更しない
- `400_domain/403_rpa_capex.js`:
  - `generateCapexInvoices` 冒頭に `LockService.getScriptLock()` による排他ロックを追加(`tryLock(30000)`、取得失敗時は `Utils.logInfo` でスキップログして即 return)
  - `buildInvRow_(invHeaders, buildCommon({...}))` を呼び出す全箇所(資産計上 L167・借入計上 L182・頭金 L198・頭金返済 L240・減価償却 P/L L272・減価償却 B/S L289・元金返済 L337・支払利息 L352)で、`buildCommon` に渡すオブジェクトに以下 2 フィールドを追加:
    ```js
    '参照元種別': 'CAPEX',
    '参照元ID': capMgrId,
    ```
  - 生成直前に `JournalRepository.findAll()` を取得し、`dto['参照元ID'] === capMgrId` が存在する場合は `Utils.logInfo` でスキップログ出力 → 当該レコードを `continue`
- `600_report/601_datamart_ingest.js`: **変更不要**(42_trn_journal を集計ソースとしていないため)

## 実装内容

1. `101_sys_config.js`:
   a. `TRN_JOUR.headers` 末尾に `"参照元種別"`, `"参照元ID"` を追加
   b. `仕訳ステータス` マスタに `'自動計上案'` を追加(`MST_DICT` カテゴリ確認後、該当カテゴリに値追加)
   c. `setupAllSchemas` 実行時、既存行の新規 2 列は空文字で埋まることを確認
2. `403_rpa_capex.js`:
   a. 冒頭 `LockService.getScriptLock()` + `lock.tryLock(30000)` + 取得失敗時のスキップ処理
   b. `JournalRepository.findAll()` の呼び出し+ `参照元ID` 検索ロジック(冪等性二次ガード)
   c. `buildInvRow_` の各呼び出し箇所(8 箇所)に `参照元種別='CAPEX'` / `参照元ID=capMgrId` を付与
   d. 既存の `isDuplicate_` による一次ガード(摘要文字列完全一致)はそのまま維持
   e. 処理完了後に `lock.releaseLock()` を `finally` 句で確実に呼ぶ
3. `601_datamart_ingest.js`: **変更なし**(仕様書「影響範囲」参照)

## 制約

- `403_rpa_capex.js` の既存メソッド(`generateCapexInvoices` 本体アルゴリズム、償却ループ、返済ループ、頭金分割、決済ラグ)を変更・削除しない
- 列参照はヘッダー名ベース(`indexOf` または `Contracts.*` の DTO 変換)。列番号ハードコード禁止(CLAUDE.md 規約)
- `Utils.addMonths` の第1引数は `"YYYY-MM"` 文字列。`Date` オブジェクトを渡さない(既存コードもこの契約を守っている)
- 科目マスタ未登録の科目名でエラーを握りつぶさない(スキップ+ `Utils.logInfo`)
- `AccountRepository._cache` のリセットは不要(読み取り専用マスタ参照のみ)
- 実シート名は `24_bud_capex_loan`(`_loan` サフィックス付き)。`24_bud_capex` ではない
- CF 計算書シート名は `81_cf_indirect`(`_monthly` なし)

## エッジケース

仕様書「エッジケース」セクションのテーブルをそのまま適用。特に以下を必ずテストする:

- `償却月数=0` → 減価償却スキップ
- `借入金額=0` かつ `月額返済額=0` → 借入イベントスキップ
- 年度またぎ(`"2025-10" + 6 → "2026-04"`)
- 科目マスタ未登録 → スキップ+ログ
- 重複実行 → 既存 `isDuplicate_` +新規 `参照元ID` 検索で二重ガード
- `返済月数=0` かつ `月額返済額>0` → 安全弁として `if (repayMonths <= 0) return;` をループ直前に追加(現状コードは `repayEndYm=''` で while ループが暴走する危険あり)

## 動作確認

1. `git commit` でローカルコミット
2. `npm run push:dev` を実行して dev 環境にデプロイ
3. dev 環境で `setupAllSchemas` を実行 → `42_trn_journal` に `参照元種別` / `参照元ID` 列が追加されることを確認
4. `24_bud_capex_loan` にテストレコードを 1 件追加(`有効フラグ=TRUE`, `管理ID=CPX_TEST01`, `取得価額=1200000`, `償却月数=60`, `借入金額=1000000`, `返済月数=60`, `月額返済額=17000`, `月額支払利息=500`, `会社支払開始年月=2026-05`, `発生日=2026-04-01`, `資産科目=機械装置`, `負債科目=長期借入金` 等)
5. メニューから「CAPEX 自動起票」を実行 → `32_wrk_invoice` に INV 行が生成されることを確認
6. ユーザー側で生成 INV の `請求ステータス` を「承認済」に変更 → Action A を実行 → `42_trn_journal` に仕訳が起票され、`参照元種別='CAPEX'` / `参照元ID='CPX_TEST01'` がセットされることを確認
7. マート更新(`setupAllSchemas` の次に実行されるマートビルダー)を実行 → P/L に減価償却費・支払利息、B/S に機械装置・長期借入金が反映されることを確認
8. 同じ `CPX_TEST01` で再度 CAPEX 自動起票 → 重複 INV が追記されないことを確認(一次ガード: `isDuplicate_` の摘要一致)
9. dev 環境で `JournalRepository.findAll()` を直接呼び出すテスト関数を用意し、`参照元ID='CPX_TEST01'` の仕訳が一覧に含まれることを確認
10. 動作確認完了後に `git push` + PR 作成 → main マージ → `npm run push:prod`

推奨実行モデル

Step内容推奨モデル理由
1101_sys_config.js DDL 拡張(headers 配列末尾に 2 列追記 + 仕訳ステータス 選択肢追加)SonnetDDL 定義箇所の特定と既存パターン踏襲
2403_rpa_capex.js の参照元メタデータ付与(buildInvRow_ 呼び出し 8 箇所)Opus複数箇所の一貫性ある修正、既存パターン理解、冪等性二次ガードの設計判断
3LockService 排他ロック追加 + 冪等性二次ガード実装Opus排他制御・冪等性実装の会計ロジック理解が必要
4動作確認スクリプト(900_test 配下 or 手動)Sonnet仕様書の動作確認チェックリストをテストケース化

複数ファイル横断・会計ロジック理解・既存コード保全が本質のため、全体として Claude Opus 推奨。特に 403_rpa_capex.js 既存ロジックの温存判断は Opus で実行すること。

変更履歴

日時変更内容
2026-04-21初版作成
2026-04-22§補強: 在庫運転資本連動 + MAS-010 / MAS-013 共通エンジン化 を追記。(A) 運転資本(在庫・売掛金・買掛金)の 3 表波及を後続 F-18b で追加する方針、(B) F18LinkageService.computeBsCfLinkage(plRows, prevBsSnapshot, paramsMap) 公開 API 契約を定義し MAS-010 / MAS-013 から共通利用、(C) 段階移行(Phase 1 CAPEX のみ → Phase 2 MAS-010 連携で API 切出 → Phase 3 運転資本追加)を明記。関連ドキュメントに MAS-010 / MAS-013 を追加

仕様書作成プロンプト

展開して表示
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】
1. **拡張思考の使い分け**: Phase 1(設計)では拡張思考をフル活用し、ファイル名・関数名・エッジケース一覧・Step分割粒度・固有名詞(列名/行番号/シート名)を**ここで完全に確定**させる。Phase 2(清書)の各Step内では拡張思考を**最小限**に抑え、Phase 1で確定した内容の書き下しに徹する。出力途中で再考しない。
2. **テキスト報告の禁止**: 「〜を作成します」等のtext-onlyでtool_useなしに終了するturnを作らない。説明は1文以内。直ちにtoolを呼ぶ。
3. **4-5分割のWrite/Edit実行**: 2-1(骨格 ~20行)/2-2(概要〜注意事項 ~300行)/2-3a(エッジケース〜人間検討事項 ~200行)/2-3b(実装プロンプト〜変更履歴 ~250行)/2-4(<details>プロンプト記録 サイズ依存)に分割。1回のWrite/Editは約300行以内。
4. **各Stepで何を書くかを具体指示**: 以下の各Stepに記載の内容を出力する。Phase 2実行中に設計判断を持ち込まない。

======================================================================
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。
CLIエージェントとして、案件 F-18「財務3表の完全連動モデリング」の開発仕様書を作成してください。
仕様書作成後、`docs/_config.json` の `nav` 配列に必ず登録してください。

## Phase 1: 実行前タスク(テキスト報告禁止。即座にツール実行)

以下を順番にReadまたはGrepで調査し、Phase 2の各Stepで書く内容を**確定**させる。
「どう書くか」の判断はすべてReadによる裏取りを行ってから記述する。Grepは「どこにあるか」の発見のみ。
推測した瞬間に手を止めてReadする(失敗パターン #18-#20 の直接対策)。

### 1-A: 案件要件の確認
- `docs/_internal/TODO_future.md` でF-18の行を検索し、**案件名・カテゴリ・Phase・優先度・概要・人間が検討すべき事項**を取得する。

### 1-B: 入力シートの構造確認
- `000_infra/002_constants.js` の `SHEET_DEFAULTS`・`ID_PREFIX_MAP` で `24_bud_capex` のデフォルト値(`取得価額`・`借入金額`・`月額返済額`・`月額支払利息`・`負債科目` 等)とIDプレフィックス(`CPX_`)を確認する。
- MCPまたはツールで `24_bud_capex` シートの実際のヘッダー一覧を取得し、**`耐用年数`・`返済期間` 等の列名が実在するか**をDDL定義と照合する。実在しない場合は仕様書の「実データ検証」セクションに「要確認」として記載する。

### 1-C: 出力先・仕訳スキーマの確認
- `000_infra/003_contracts.js` の `JournalEntryDTO` の全フィールド名を確認する。特に以下を把握する:
    - `仕訳ステータス` の既存値: `"自動計上" | "手動" | "仕訳振替"`
    - `管理ID`・`CF支払ID` 等の既存メタデータ列の用途
- `100_config/101_sys_config.js` の `setupAllSchemas` 内で `42_trn_journal` のDDLスキーマ定義(カラム一覧・バリデーション設定)を確認し、**新カラム(`参照元種別`・`参照元ID`)および `仕訳ステータス` の選択肢追加の追記箇所**を特定する。

### 1-D: 既存CAPEXコードの確認(最重要)
- `400_domain/403_rpa_capex.js` を全体Readし、以下を確認する:
    - 固定資産計上・減価償却・借入返済の仕訳生成が**既に実装されているか**
    - 既存メソッド名・引数・返り値の型
    - 本案件が新規実装すべき処理と、既存コードを再利用できる処理の境界
- `400_domain/407_rpa_orchestrator.js` で `RPAService` の公開APIを確認し、本案件の処理をどのメニューエントリポイントから呼ぶか判断する。

### 1-E: マートビルダーの集計ロジック確認
- `600_report/601_datamart_ingest.js` をReadし、`42_trn_journal` から財務諸表へのデータ集計フローと、**`仕訳ステータス` でのフィルタリング条件**(現在どの値を集計対象とするか)を確認する。
- `600_report/` 配下のCF計算書を生成しているファイル(`608_datamart_render.js` または他のファイル)をReadし、CF計算書シートの**実際のシート名**を確認する(Geminiが参照した `81_cf_indirect_monthly` は実在確認が取れていないため、必ずReadで裏取りすること)。

### 1-F: ユーティリティ・リポジトリの確認
- `000_infra/004_utils.js` で `addMonths(ymStr, months)` の引数型(`"YYYY-MM"` 文字列、Dateオブジェクト不可)と返り値を確認する。`parseDateToYm` も同様に確認する。
- `200_data/202_repository.js` で `JournalRepository.append(dtos)` と `AccountRepository.findAsMap()` のシグネチャ・返り値の型(`findAsMap` は `{ stmt: string, cat: string }` のマップ)を確認する。

### 1-G: 参考パターンの確認
- `docs/_internal/failure_patterns.md` で以下を確認する:
    - #16「合算マッチで同じSTLが再利用された」→ `matched=true` ロックパターンを本案件の冪等性ガード(`参照元ID` 検索によるスキップ)に応用する
    - #21-#24(数式設計の落とし穴)→ マートのラベル解決はGAS側で完結させる原則
- `docs/dev/dev_mas-076_idempotency_fix.md` で冪等性実装パターン(既存仕訳の存在確認ロジック)を確認する。

## Phase 2: 仕様書の分割作成

出力先: `docs/dev/dev_mas-018_financial_statement_linkage.md`
**【重要】1回のWrite/Editは300行以内。以下の5 Stepに分割して実行すること。**

### Step 2-1: 骨格の作成 (File Write, ~20行)
以下の見出しのみのファイルを新規作成する(本文は空で可):
```
# MAS-018: 財務3表の完全連動モデリング
## 概要
## 目的
## 現在のコード
## 修正方針
## 影響範囲
## 注意事項
## エッジケース
## 実データ検証
## 関連ドキュメント
## 人間が検討すべき事項
## 実装プロンプト(Claude Code 用)
## 推奨実行モデル
## 変更履歴
## 仕様書作成プロンプト
```

### Step 2-2: 前半セクションの追記 (File Edit または Bash heredoc, ~300行)
以下の内容を書く:

- **概要テーブル**: 案件ID=F-18、カテゴリ=新機能(FP&A)、Phase/優先度=TODO_future.mdから転記、対象ファイル=`400_domain/403_rpa_capex.js`(既存拡張または新規)・`100_config/101_sys_config.js`・`600_report/601_datamart_ingest.js`(フィルタ修正)、前提案件=なし(Phase 1-A調査結果で更新)
- **目的**: Phase 1-Aで取得した概要をもとに1〜3文で記述
- **現在のコード**: Phase 1-Dで確認した `403_rpa_capex.js` の既存実装状況(ファイル名・関数名・行番号を明記)。本案件で新規追加が必要な処理を特定する
- **修正方針**: 以下を盛り込む(Phase 1の調査結果で固有名詞を補完すること)
    - **全体アーキテクチャ**: `24_bud_capex` の各レコードをインプットとし、以下3イベントに対応する `JournalEntryDTO` 配列を生成して `JournalRepository.append()` で `42_trn_journal` に追記する
        1. **固定資産計上**: 取得価額に基づく固定資産B/S計上 + 現金/負債勘定への反映(1回限り)
        2. **減価償却**: 耐用年数にわたる毎月の減価償却費(P/L)・減価償却累計額(B/S)の計上(定額法。月次 = 取得価額 ÷ 耐用年数月数)
        3. **借入返済**: 返済期間にわたる毎月の元金返済(B/S)・支払利息(P/L)の計上
    - **計上月の計算**: `Utils.addMonths(startYm, i)` を使用(引数は `"YYYY-MM"` 文字列)
    - **冪等性ガード(DDL変更を伴う)**:
        - `101_sys_config.js` の `42_trn_journal` DDL定義に `参照元種別`(例: `'CAPEX'`)・`参照元ID`(例: `'CPX_0001'`)カラムを追加
        - 仕訳生成ロジック冒頭で `JournalRepository.findAll()` の結果から `参照元ID` が一致する仕訳を検索し、存在する場合は `Utils.logInfo` でスキップログを出力して処理を中断
    - **Human-in-the-Loop(承認フロー)**:
        - `101_sys_config.js` の `42_trn_journal` DDL定義の `仕訳ステータス` 選択肢に `'自動計上案'` を追加(既存値: `"自動計上"` / `"手動"` / `"仕訳振替"`)
        - 自動生成仕訳はすべて `仕訳ステータス='自動計上案'` で登録
        - `601_datamart_ingest.js` の集計フィルタに `仕訳ステータス !== '自動計上案'` の除外条件を追加(Phase 1-Eで確認した既存フィルタ条件と整合させる)
        - ユーザーが手動で `'自動計上'` に変更後、マート再更新で財務諸表に反映
    - **排他制御**: `LockService.getScriptLock()` で処理全体をロック
- **影響範囲**: 変更ファイル(上記3ファイル)・変更量・既存処理への影響(既存のRPA起票・マート集計への影響範囲)
- **注意事項**:
    - `403_rpa_capex.js` の既存メソッドを変更・削除しない(Phase 1-D調査で確認した既存処理を明記)
    - `Utils.addMonths` の第1引数は `"YYYY-MM"` 文字列。`Date` オブジェクトを渡すと正しく動作しない(失敗パターン #17)
    - 計画変更時の非自動更新: 元データ(`24_bud_capex`)が変更されても既存仕訳は自動更新しない。修正は手動で行うことを前提とする
    - `AccountRepository.findAsMap()` で科目マスタ未登録の科目名が使用された場合は、エラーを握りつぶさずスキップ+`Utils.logInfo` でログ出力する(CLAUDE.md: 科目マスタ未登録はエラー、キーワード推測禁止)
    - 列参照はヘッダー名ベース(`indexOf`)。列番号ハードコード禁止(CLAUDE.md規約)

### Step 2-3a: エッジケース〜人間検討事項の追記 (File Edit または Bash, ~200行)
(省略。本仕様書「エッジケース」「実データ検証」「関連ドキュメント」「人間が検討すべき事項」セクション参照)

### Step 2-3b: 実装プロンプト〜変更履歴の追記 (File Edit または Bash, ~250行)
(省略。本仕様書「実装プロンプト(Claude Code 用)」「推奨実行モデル」「変更履歴」セクション参照)

### Step 2-4: 仕様書作成プロンプトの記録 (File Edit または Bash, サイズ依存)
末尾の `## 仕様書作成プロンプト` セクションに `<details><summary>展開して表示</summary>` ブロックを設け、この `<instruction>` 全文(添削後の最終版)を記録する。

## Phase 3: 後処理(テキスト報告禁止。即座にツール実行)

### 3-A: `_config.json` への登録
`docs/_config.json` の `nav` 配列の §E.5(FP&A・レポーティング)に以下を追加する:
```json
{ "file": "dev/dev_mas-018_financial_statement_linkage.md", "title": "E.5.X MAS-018 財務3表の完全連動モデリング" }
```

### 3-B: changelog 追記
`docs/_internal/changelog.md` の先頭(ヘッダー直後)に以下を追記する:
```
| 2026-04-20 | [dev_mas-018_financial_statement_linkage.md](dev_mas-018_financial_statement_linkage.md) | 初版作成。財務3表完全連動モデリングの開発仕様書 |
```

### 3-C: コミット&プッシュ
```bash
git add docs/dev/dev_mas-018_financial_statement_linkage.md docs/_internal/changelog.md docs/_config.json
git commit -m "docs: MAS-018 財務3表完全連動モデリングの開発仕様書を作成

24_bud_capexをインプットに固定資産計上・減価償却・借入返済の3イベント仕訳を自動生成する設計。
Human-in-the-Loopとして自動計上案ステータスによる承認フローを採用。冪等性は参照元IDで担保。

https://claude.ai/code/session_XXXXX"
git push -u origin {現在のブランチ}
```