概要

項目内容
案件IDMAS-115
カテゴリ財務諸表 UI 改善(データマート)
PhaseP2
優先度★★
所要時間8〜12時間(Step1〜3の実装+動作確認)
対象ファイル(既存への追記)600_report/602_datamart_main.js / 100_config/101_sys_config.js / templates/operations_sidebar.html
対象ファイル(新規)600_report/611_datamart_unified.js(仮名。レンダラの分離を推奨)
前提案件MAS-094(基準年月プルダウン。buildDataMartWithCustomBoundary を再利用)
関連案件MAS-093(isActualOnly 実績専用モード)/ MAS-095(B/S スナップ実績専用化)/ MAS-025(予実差異)/ MAS-001(P/L予実差異)

目的

現状、P/L・B/S・CF の財務諸表は 61_pl_monthly / 62_pl_ytd / 63_pl_monthly_plan / 64_pl_ytd_plan / 65_pl_variance / 71_bs / 72_bs_snap / 73_bs_plan / 81_cf_indirect / 81b_cf_indirect_ytd / 82_cf_indirect_plan / 82b_cf_indirect_plan_ytd12 タブに分散しており、ユーザーが「今月の実績 P/L を単月で見たい」「計画比で累積 B/S を見たい」といった目的ごとに複数タブを跨ぐ必要がある。スプレッドシート左下のタブ一覧が肥大化し、目的のデータへ到達するまでの操作コストが高い。

MAS-115 では、P/L・B/S・間接法 CF をそれぞれ 1 タブに統合し、タブ内 A1 セルに配置する「表示モード」プルダウンで切替できる UX に変更する。切替は onEdit トリガーで即時に再描画し、12 タブ → 4〜5 タブ(P/L 1 + B/S 1 + CF間接 1 + CF日次 1〜2)へ 60% 以上の削減を目指す。なお日次 CF(83/84/85)は性質が異なるため統合対象外とする。

現在のコード

既存シートと KEY マッピング(600_report/602_datamart_main.js L172-188 および 100_config/101_sys_config.js L609-620 で確認済み)

KEYデフォルト名種別備考
PL_M_ACT61_pl_monthlyP/L 実績 単月isActualOnly=true で描画
PL_Y_ACT62_pl_ytdP/L 実績 累積isActualOnly=true で描画
PL_M_PLAN63_pl_monthly_planP/L 計画 単月isActualOnly=false で描画
PL_Y_PLAN64_pl_ytd_planP/L 計画 累積isActualOnly=false で描画
PL_VAR65_pl_varianceP/L 予実差異MAS-001 で MAS-025 により分離済
BS_ACT71_bsB/S 実績isActualOnly=true で描画
BS_SNAP72_bs_snapB/S スナップショットMAS-095 で実績専用化済み
BS_PLAN73_bs_planB/S 計画isActualOnly=false で描画
CF_IND_ACT81_cf_indirect間接法 CF 実績 単月MAS-093 で実績専用対応済
CF_IND_ACT_YTD81b_cf_indirect_ytd間接法 CF 実績 累積同上
CF_IND_PLAN82_cf_indirect_plan間接法 CF 計画 単月
CF_IND_PLAN_YTD82b_cf_indirect_plan_ytd間接法 CF 計画 累積
CF_D_ACT83_cf_daily日次 CF 実績統合対象外(本案件では変更しない)
CF_D_PLAN84_cf_daily_plan日次 CF 計画統合対象外
CF_D_REAL85_cf_daily_actual日次 CF 実績(銀行残高ベース)統合対象外

既存レンダラ関数(600_report/602_datamart_main.js

関数所在シグネチャ役割
buildBudgetTrendDataMart602 L159function buildBudgetTrendDataMart(overrideBoundary)マート更新の公開エントリ。全シートに一括出力
dmIngestData_601(ctx, sheetInv, sheetBank, sheetAcct)32/33/11 タブを読み込み ctx を構築
dmCalcPl_ / dmCalcBs_ / dmCalcCf_603/604/605(ctx)martPl / martBs から P/L・B/S・CF の集計を計算
dmBuildPlOutput_603 L199(ctx) → {outM, outY, fmtM, fmtY, yoyColCount}P/L の出力配列(単月=outM / 累積=outY)を同時生成
dmBuildBsOutput_604 L145(ctx) → {outB, fmtB}B/S の出力配列を生成
dmBuildCfOutput_605 L52(ctx) → {outC, outCY, fmtC, fmtCY}CF の出力配列(単月=outC / 累積=outCY)を同時生成
dmApplyDwhFormat_608(描画)(sheet, out, fmt, 'PL'|'BS'|'CF', targetMonthsWithActBgt)シートに書き出し・書式適用
buildDataMartWithCustomBoundary602 L386()MAS-094 の基準年月プルダウン(ダイアログ方式)

isActualOnly フラグの実際の型と挙動

  • : JavaScript 素の booleanctx.isActualOnly = true; L243、計画側は isActualOnly: false L267)
  • 参照箇所: 603 L204 / 604 L148 / 605 L57
  • 挙動: true のとき filterValues() / filterWithRecalcTotal() で境界月以降を空白に除去し、ヘッダーから「(実績)/(予算)」ラベルを落とす。false のときは全月表示+ラベル付き

既存の onEdit 定義(100_config/101_sys_config.js L363-413)

  • GASonEdit100_config/101_sys_config.js L363 で単一定義されている(300_ui/301_ui_assist.js には存在しない。同ファイルの handleUxAssist(e) が L412 で呼び出されるだけ)
  • 既存分岐は sheetName === e.range.getSheet().getName()row / col による判定(getA1Notation() は使っていない)
  • 既存分岐リスト: (a) Constants.CONFIG_SHEET の key/logic 生成、(b) 36_wrk_bank_import のマッチ方法自動更新、(c) 33_wrk_bank/32_wrk_invoice仕訳発行後編集監査、(d) handleUxAssist(e) への委譲

メニュー構造の現状(100_config/101_sys_config.js L299-307)

onOpen()🚀 BizLP メニュー 1 本のみを生成し、個別のマート更新系ボタンは全て templates/operations_sidebar.html のサイドバーに移設されている。MAS-094 仕様書内に記載された 📊 マート更新 トップメニューは現行コードでは廃止されている点に注意(新規メニューを増やすのではなく、サイドバー HTML に追記する運用)。

BudgetRepository の不在(Phase 1 で Read 確認済)

  • 200_data/202_repository.js に定義されている Repository は OrderRepository / InvoiceRepository / BankTxRepository / JournalRepository / AccountRepository の 5 つのみ
  • BudgetRepository は未実装。本案件は既存 dmIngestData_ が返す ctx.finalUnionData を再利用するため、41_trn_budget への直接アクセスは原則不要。仮に新規に読み込む必要が生じた場合は 41_trn_budget.getDataRange().getValues() + ヘッダー名ベース indexOf 参照で暫定対応する(Repository 新設は別案件として分離)

動的生成タブの扱い(CLAUDE.md 記載)

CLAUDE.md の「DDL (setupAllSchemas) で管理されないタブ」に列挙される動的生成タブ: 03_sys_params / 75_ss_equity_changes / 76_notes / 77_pj_raw / 78_pj_pl / 91_fs_bs / 92_fs_pl / 93_kpi_dashboard / 90_test_results

一方で 61〜65 / 71〜73 / 81〜82b は DDL 管理対象setupAllSchemas の対象)であり、setupAllSchemas 再実行でプルダウンが消失する可能性がある。統合タブを DDL 管理対象にするか動的生成扱いにするかは Step 1 の実装方針で決定する(本仕様書では DDL 管理対象として登録する方針を推奨)。

修正方針

Step 1: 統合シートの作成と初期化(Claude Sonnet 4.6 推奨)

1-a: 統合シートの番号帯・名称

本案件では以下の 3 シートを新設する。既存番号帯と重複しない 6X / 7X / 8X の空き番号を選定する:

新規シート名(候補)KEY(新設)役割既存対応
60_fs_pl_unifiedFS_PL_UP/L 統合61/62/63/64 を集約
70_fs_bs_unifiedFS_BS_UB/S 統合71/72/73 を集約
80_fs_cf_unifiedFS_CF_U間接法 CF 統合81/81b/82/82b を集約

注記: シート番号 60 / 70 / 80 は現行未使用(Phase 1 調査で確認)。ただし将来的に DDL で予約される可能性があるため、最終的な番号採番は実装着手時に 101_sys_config.jssetupAllSchemas スキーマ一覧と照合して確定する(「要確認」扱い)。

1-b: プルダウン(データバリデーション)の設置

各統合シートの A1 セルDataValidation を設置する。選択肢は以下:

  • P/L 統合(60_fs_pl_unified:
    • 実績・単月(既存 61 相当、isActualOnly=trueviewMode='monthly'
    • 実績・累積(既存 62 相当、isActualOnly=trueviewMode='ytd'
    • 計画含む・単月(既存 63 相当、isActualOnly=falseviewMode='monthly'
    • 計画含む・累積(既存 64 相当、isActualOnly=falseviewMode='ytd'
  • B/S 統合(70_fs_bs_unified:
    • 実績(既存 71 相当)
    • スナップショット(月末時点)(既存 72 相当、viewMode='snap'
    • 計画含む(既存 73 相当、isActualOnly=false
  • CF 統合(80_fs_cf_unified:
    • 実績・単月(既存 81 相当)
    • 実績・累積(既存 81b 相当)
    • 計画含む・単月(既存 82 相当)
    • 計画含む・累積(既存 82b 相当)

注記: CLAUDE.md コーディング規約「シートへの書き込み位置は列 B (ID列) で最終行を判定(列 A のチェックボックス回避)」は 32_wrk_invoice 等のデータ入力シートに適用される規約。財務諸表レポートシート(本案件のアウトプット)は 1 行目=ヘッダー、2 行目以降=集計結果で、チェックボックス列は存在しないため A1 セルにプルダウンを設置して問題ない(既存 targetMonthsWithActBgt ヘッダーが列 A〜列 P に並ぶレイアウトと整合させ、プルダウンは列 A 1 行目のヘッダー文字列の代わりに配置するか、または 1 行目をプルダウン専用行・2 行目以降に既存のヘッダーを下げる構造に変更する。後者のほうが既存 dmApplyDwhFormat_ との衝突が少ない)。

1-c: 初期化フロー

プルダウンの初期設置は setupAllSchemas に統合するのが望ましい。代替として buildBudgetTrendDataMart 内の「出力書き込み」直前に ensureUnifiedSheetDropdown_(sheet) を挟み、毎回のマート更新で冪等的に設置する方式でもよい(既存 dmApplyDwhFormat_ との同居が容易)。両方式の長所短所は Step 1 実装時に人間判断で決める(「人間が検討すべき事項」に記載)。

1-d: 初期表示モード

プルダウン未選択状態(空セル)では 実績・単月 をデフォルトとしてフォールバック描画する。handleUnifiedFsEdit_ の冒頭で e.value が空のときは 実績・単月 をそのまま採用する。

Step 2: onEdit トリガーへの分岐追加(Claude Sonnet 4.6 推奨)

2-a: 挿入位置

100_config/101_sys_config.js L363-413 の既存 onEdit(e) 関数内、if (sheetName === Constants.CONFIG_SHEET ...) の分岐(L366)のif (sheetName === '36_wrk_bank_import') の分岐(L372)のに、MAS-115 専用分岐を挿入する:

  // S-43: 財務諸表統合タブのプルダウン変更を検知して再描画
  if (sheetName === '60_fs_pl_unified' || sheetName === '70_fs_bs_unified' || sheetName === '80_fs_cf_unified') {
    if (e.range.getA1Notation() === 'A1') {
      try { handleUnifiedFsEdit_(e); } catch (err) { Utils.logError('handleUnifiedFsEdit_', err); }
      return;
    }
  }

return することで後続の handleUxAssist(e) を呼ばない(統合タブは手入力対象ではないため)。

2-b: LockService 排他制御

handleUnifiedFsEdit_(e) の冒頭で以下の排他制御を行う:

var lock = LockService.getScriptLock();
if (!lock.tryLock(3000)) {
  Utils.toastResult('unifiedFs', '他の処理が実行中のため再描画をスキップしました。数秒後に再操作してください。');
  return;
}
try {
  // 再描画本体
} finally {
  lock.releaseLock();
}
  • tryLock(3000) で 3 秒待機。取得失敗時はトーストで通知して終了(waitLock ではなく tryLock を使う理由は、UI 操作の応答性を優先するため。マート更新など長時間処理と競合すると 3 秒でタイムアウトするが、再操作で済む)
  • finallyreleaseLock() を呼ぶ。エラー発生時もロックが残らない

2-c: MAS-094 との共存

MAS-094 は現在ダイアログ方式(buildDataMartWithCustomBoundary)のため同一 onEdit には干渉しない。ただし将来 MAS-094 が A1 セルプルダウン化される可能性があるため、e.range.getA1Notation() で判定する構造にしておく(同じ A1 セルを両機能が使うことは避ける。例えば MAS-094 は A2 セル、MAS-115 は A1 セル、と明示的に分担する)。

Step 3: 再描画ロジックの実装(Claude Opus 4.6 推奨)

3-a: 新規ファイル 600_report/611_datamart_unified.js を作成

以下の関数を定義する:

  • handleUnifiedFsEdit_(e)onEdit から呼ばれるエントリ。シート名で P/L / B/S / CF を分岐
  • renderUnifiedPl_(mode) — P/L 統合シートに描画。mode{ isActualOnly, viewMode } のオブジェクト
  • renderUnifiedBs_(mode) — B/S 統合シートに描画
  • renderUnifiedCf_(mode) — CF 統合シートに描画
  • ensureUnifiedSheetDropdown_(sheet, choices) — A1 プルダウンを冪等に設置

3-b: 既存マートビルダの再利用方針

既存 buildBudgetTrendDataMart12 シート全てを一括再描画する重い処理(dmIngestData_ で 32/33 タブをフルスキャン、実績と計画の 2 パス dmProcessAllEvents_ / dmCalcPl_ 等)。onEdit からの再描画では 1 モードのみ描画すれば十分なため、以下の方針で軽量化する:

方式 A(推奨): buildBudgetTrendDataMart のロジックを部分抽出

  • dmIngestData_ + dmProcessAllEvents_ + dmCalc*_ までは共通で実行(実績/計画どちらか一方のみ)
  • dmBuild*Output_ の結果を dmApplyDwhFormat_ で統合シートに書き出す
  • 既存の 12 タブへの書き出しはスキップ

方式 B: buildBudgetTrendDataMart をそのまま呼び、最後に統合シートへのコピー処理を追加

  • 実装は簡単だが重い(P/L 1 枚見るだけで 12 枚全再描画)

Step 3 では方式 A を採用する。buildBudgetTrendDataMart をリファクタして「実績 ctx 構築部」「計画 ctx 構築部」「シート書き出し部」の 3 関数に分割する(buildActualCtx_() / buildPlanCtx_() / writeToSheets_())。統合シート再描画はこの 3 関数のうち必要なものだけを呼ぶ。

リファクタリングの影響範囲: buildBudgetTrendDataMart 本体(~220 行)を分割。既存の呼び出し側(buildBudgetTrendDataMart / buildDataMartWithCustomBoundary)は引数なし呼び出しを維持し、内部的に分割後関数を順に呼ぶラッパー構造とする。

3-c: 表示モードと isActualOnly の対応

既存の isActualOnly(boolean)は「実績のみフィルタ」の意味であり、統合タブの viewMode(monthly/ytd/snap)とは直交する概念。以下のマトリクスで実際のレンダラ出力配列を切り替える:

プルダウン選択isActualOnly出力配列説明
実績・単月(P/L)trueplOut.outM境界月以降空白、実績のみ
実績・累積(P/L)trueplOut.outY累積ビュー
計画含む・単月(P/L)falseplanPlOut.outM計画パイプライン込み
計画含む・累積(P/L)falseplanPlOut.outY同上
実績(B/S)truebsOut.outB
スナップショット(B/S)truedmRenderBsSnapshot_ 相当月末確定残高
計画含む(B/S)falseplanBsOut.outB
実績・単月(CF)truecfOut.outC
実績・累積(CF)truecfOut.outCY
計画含む・単月(CF)falseplanCfOut.outC
計画含む・累積(CF)falseplanCfOut.outCY

3-d: 処理中表示

handleUnifiedFsEdit_ の冒頭で Utils.toastResult('unifiedFs', '更新中...') を呼び、再描画完了時に再度 Utils.toastResult('unifiedFs', '完了') を呼ぶ。数秒以上かかる場合にユーザーが操作フィードバックを得られる。

3-e: SpreadsheetApp.flush() の挿入

既存コードに SpreadsheetApp.flush() の使用箇所はないが、再描画完了後に 1 回だけ flush() を呼ぶことで、プルダウン変更 → 画面反映のラグを軽減する。dmApplyDwhFormat_ の直後、lock.releaseLock() の直前に挿入。

影響範囲

区分ファイル変更内容変更量
追記600_report/602_datamart_main.jsbuildBudgetTrendDataMart を 3 関数に分割(buildActualCtx_ / buildPlanCtx_ / writeToSheets_)し、既存ラッパーとして維持大(リファクタ中心で ~250 行の再配置)
新規600_report/611_datamart_unified.js統合タブ用のレンダラ(handleUnifiedFsEdit_ / renderUnifiedPl_ / renderUnifiedBs_ / renderUnifiedCf_ / ensureUnifiedSheetDropdown_中(~300 行)
追記100_config/101_sys_config.jsonEdit に MAS-115 分岐 1 ブロック追加、setupAllSchemasSYS_CONFIG へ 3 KEY(FS_PL_U / FS_BS_U / FS_CF_U)追加、必要なら DDL スキーマ登録小〜中
追記templates/operations_sidebar.html§📊 マート更新 セクションに「統合タブを初期化」ボタン 1 つ追加(初回セットアップ用)小(1 ブロック)
既存維持61〜65 / 71〜73 / 81〜82b旧タブは並行稼働期間中は出力を継続。削除は段階移行(別案件)変更なし

注意事項

  1. BudgetRepository 不在への対応: 200_data/202_repository.jsBudgetRepository は存在しない(Phase 1 で Read 確認済)。本案件では既存 dmIngestData_ / dmIngestPlanData_ / dmIngestPipelinePlanData_ が返す ctx.finalUnionData を再利用し、41_trn_budget への直接アクセスは行わない。将来 Repository 化する場合は MAS-115 のスコープ外とする。
  2. 既存 onEdit 分岐の破壊防止: L364 の if (row === 1) return; で「1 行目の編集はスキップ」されている点に注意。MAS-115 では A1 セルを編集対象とするため、この分岐を経由しない書き換えが必要。具体的には、A1 編集検出を row === 1 チェックよりに行うか、row === 1 分岐の中で A1 判定を行う。推奨は後者(既存の仕訳振り分けロジックなど他の row > 1 前提の分岐を壊さない)。
  3. DDL 管理対象シートの扱い: 統合シート(60_fs_pl_unified 等)は DDL 管理対象として setupAllSchemas に登録する方針。DDL 再実行時にプルダウンが消失しないよう setVali で明示的に再設定するか、スキーマ定義に dataValidation プロパティを組み込む。
  4. CLAUDE.md コーディング規約遵守: 列参照は全てヘッダー名ベース(indexOf)で行い、列番号ハードコード禁止(既存 dmApplyDwhFormat_targetMonthsWithActBgt 配列を引数で受けるためこの規約は既に守られている)。
  5. 旧タブの並行稼働: 移行期間中(推奨 1 ヶ月)は 61〜65 / 71〜73 / 81〜82b の旧タブへの出力を継続する。既存 buildBudgetTrendDataMart の書き出しロジックを削除しないこと。旧タブの廃止は別案件(MAS-115-follow)として分離し、安定確認後に実施する。
  6. MAS-094 との A1 セル衝突回避: MAS-094 は現時点でダイアログ方式だが、将来プルダウン化される場合は MAS-094 用セルを A2、MAS-115 用セルを A1 と明示的に分担する。
  7. LockService のセッション範囲: LockService.getScriptLock() はスクリプト全体で 1 つのロックを共有するため、マート更新実行中にプルダウン操作すると 3 秒で tryLock が失敗する。これは正しい挙動(二重再描画を防ぐため)だが、ユーザーへの通知文言(Utils.toastResult の第 2 引数)で理由を明示する。
  8. isActualOnly の既存参照箇所(603/604/605)の不変性: isActualOnly を参照する既存ロジックは変更しない。統合タブでも全く同じ ctx.isActualOnly + 出力配列(outM/outY/outB/outC/outCY)を使い回す。
  9. dmApplyDwhFormat_ の第 1 引数 sheet は統合シートに切替可能: 既存の書き出し関数 dmApplyDwhFormat_(sheet, out, fmt, 'PL'\|'BS'\|'CF', targetMonthsWithActBgt) はシートを引数で受けるため、統合シートを渡すだけで既存フォーマット処理を再利用できる。

エッジケース

#条件表示値/挙動理由
E01プルダウン未選択(A1 セルが空)デフォルト 実績・単月 で描画初回アクセス時の UX。ユーザー操作なしでも壊れない
E0242_trn_journal / 41_trn_budget が空エラーなく空の表を描画(列ヘッダー・科目行は維持)データ未投入時の安全な初期表示
E03P/L の売上高 = 0(比率列でのゼロ除算)"-" 表示(failure_patterns.md #2 に準拠)既存 dmBuild*Output_ が既にこの挙動を実装済。そのまま継承
E04onEdit の多重実行(ユーザーが連続でプルダウンを切替)LockService.tryLock(3000) 失敗 → Utils.toastResult('unifiedFs', '他の処理が実行中...') 通知してスキップパフォーマンス保護
E05MAS-094 のプルダウンと MAS-115 のプルダウンが同一 onEdit で発火e.range.getA1Notation()sheetName で分岐し、それぞれの処理を独立実行MAS-094 との共存(現状は別シート/別メニュー方式で衝突しない)
E06既存マートビルダ関数のリファクタ中に旧関数呼び出しが残存デプロイ前に grep -rn "dmBuildPlOutput_|dmBuildBsOutput_|dmBuildCfOutput_" 600_report/ で全参照を確認(failure_patterns.md #7 に準拠)ファイル分割時の未定義関数エラー防止
E07統合シート未作成の状態でプルダウン操作getSheetByKey('FS_PL_U', '60_fs_pl_unified') が null を返すため handleUnifiedFsEdit_ が早期 return。Utils.toastResult で「統合タブ未初期化」を通知未セットアップ環境での安全なフェイル
E08setupAllSchemas 実行でプルダウンが消えるDDL 側で dataValidation を再設定するか、ensureUnifiedSheetDropdown_ を毎マート更新で冪等に呼ぶDDL との整合性
E09境界月(boundaryMonthStr)が未確定(1900-01既存 buildBudgetTrendDataMart L237 の処理をそのまま流用し、実績反映: なし 表示既存仕様を継承
E10プルダウン選択肢以外の文字列が A1 に書き込まれるDataValidation.requireValueInList() で入力を拒否。万が一通った場合は handleUnifiedFsEdit_ 内の switch デフォルトで 実績・単月 にフォールバック異常入力の安全な処理
E11スナップショット(B/S)モードで実績月がないdmRenderBsSnapshot_sheetBs 依存のため、統合タブではセクショナル描画のみ実装。月末残高が 0 の月は空白表示既存 72_bs_snap の挙動を踏襲
E12SpreadsheetApp.flush() の重複呼び出し冪等なので安全。ただしマート更新本体との競合を避けるため、LockService ブロック内で 1 回だけ呼ぶパフォーマンス
E13プルダウン操作と buildBudgetTrendDataMart 実行が同時LockService 競合で tryLock 失敗 → ユーザーに再操作依頼二重書き込み防止
E14統合シート番号(60/70/80)が将来 DDL で予約される実装着手時に 101_sys_config.js 内のスキーマ一覧と getSheetByKey の登録済み KEY を grep で確認し、未使用を再確認番号衝突防止
E15handleUnifiedFsEdit_ 内で例外発生try/catchUtils.logError + SpreadsheetApp.getUi().alert 通知。ロックは finally で確実に解放安全なエラーハンドリング

実データ検証(実装前に MCP / GAS 実機で確認すべき項目)

#確認項目確認方法理由
V01現行 61_pl_monthly / 62_pl_ytd / 71_bs / 81_cf_indirect に実データがあることdev 環境でマート更新実行後、各シートの 2〜5 行目を目視確認統合タブ描画後の比較対象を確保
V02プルダウン選択肢文字列(候補値)の最終決定TODO_future.md の記載と「人間が検討すべき事項」を突き合わせ、UX ワーディングを確定する実装後の変更はプルダウン再設定+ onEdit switch の書き換えが必要で手戻りコスト大
V03isActualOnly の実際の格納型602 L243 を Read 確認済(true)。スプレッドシートセルからの読み取り値ではなく ctx オブジェクトの JS boolean統合タブのプルダウン値(文字列)→ boolean 変換ロジックを正しく実装するため
V0441_trn_budget に対象月のデータが存在するか41 タブを開き、対象期の 12 ヶ月分の予算データが 1 件以上存在することを確認予算ゼロ月の描画確認(E02 ケース)
V05統合タブ番号 60/70/80 が既存・計画中スキーマと衝突しないかgrep -rn "60_|70_|80_" 100_config/ 600_report/ で既存参照を全件チェック番号衝突防止(E14 ケース)
V06LockService.tryLock(3000) の挙動マート更新中にプルダウン操作して、トースト通知が出ることを手動検証E04 / E13 の挙動確認
V07setupAllSchemas 再実行でプルダウンが消えないことdev 環境で統合タブ初期化 → setupAllSchemas → プルダウンが残存していることを目視E08 の挙動確認

関連ドキュメント

仕様書 / ファイル関連箇所
dev_mas-094_boundary_month_selector.md基準年月プルダウンの実装方式。MAS-115 の onEdit 分岐と共存設計
dev_mas-093_cf_actual_only.mdisActualOnly パターンの CF への適用。MAS-115 でも同フラグを流用
dev_mas-095_bs_snap_actual_only.mdB/S スナップショットの実績専用化パターン。統合タブの「スナップショット」モードで参照
dev_mas-001_variance_analysis.md財務諸表系仕様書のフォーマット・エッジケース記述の深度(参考)
dev_mas-025_budget_variance.md予算 vs 実績差異分析。MAS-001 分離後の 65 タブと統合タブの共存方針
docs/_internal/failure_patterns.md #2ゼロ除算フォールバック("-" 表示)
docs/_internal/failure_patterns.md #7ファイル分割/リファクタリング時の旧関数残存
CLAUDE.md動作確認テスト(600_report/6*_datamart_*.js → マート更新テスト)/列参照のヘッダー名ベース規約

人間が検討すべき事項

以下は TODO_future.md に記載された事項+本仕様策定で追加抽出した事項:

  1. プルダウンの配置場所: A1 セル固定 vs フローティング(データバリデーションのみ)。本仕様では A1 セル固定案を推奨したが、最終判断は UX 要件次第(TODO_future.md より転記)。
  2. 切替時の再描画速度: データ量が多いと遅延する可能性(TODO_future.md より転記)。方式 A(ctx 構築部 + 出力部の分割)で軽量化する設計だが、実測で 3 秒を超える場合は tryLock タイムアウトの調整が必要。
  3. 既存タブの廃止タイミング: 並行稼働期間の設定(TODO_future.md より転記)。推奨 1 ヶ月。廃止ステップ: (a) 旧タブ上部に「➡️ 統合タブへ移動」バナー設置 → (b) 旧タブ非表示化(シートを非表示、データは保持) → (c) 安定確認(最低 2 週間)後に完全削除。
  4. GCP 移行(MAS-238)後の投資対効果: WebUI で実現する前提の場合、GAS フェーズでの実装工数の投資対効果判断(TODO_future.md より転記)。移行見込み時期と GAS フェーズの残存期間から ROI を評価。
  5. 統合シートの番号帯・シート名の最終確定: 60_fs_pl_unified / 70_fs_bs_unified / 80_fs_cf_unified は候補。番号衝突確認(V05 / E14)後に決定。
  6. プルダウン選択肢文字列の確定: 本仕様では 実績・単月 / 実績・累積 / 計画含む・単月 / 計画含む・累積 を提案。ユーザー向け UX として「実績」「見込み」「計画」等の呼称バリエーションの検討余地あり(V02)。
  7. BudgetRepository の設計判断: 本案件では直接アクセス不要だが、将来の別案件で新規 Repository クラス作成 vs 41_trn_budget 直接アクセスのどちらを採用するか。
  8. buildBudgetTrendDataMart の 3 関数分割: 方式 A を採用する場合、リファクタの影響範囲が広い。既存テスト(901_test_runner.js)でマート更新系テストが存在する場合はリグレッション確認が必要。
  9. プルダウン初期化の責務: DDL (setupAllSchemas) で担当 vs 毎マート更新で冪等設置 vs 初回専用のセットアップ関数 — 3 案の選択(1-c)。
  10. 旧タブ関連の既存テストケース更新: 旧タブ廃止時に 901_test_runner.js のマート更新テストを更新する必要あり。廃止フェーズで別 PR として分離。
  11. A1 / A2 の配置方針: MAS-094 が将来 A1 プルダウン化される場合の役割分担(MAS-094 は A2、MAS-115 は A1 等の明示化)。

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

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-115「財務諸表タブの統合(プルダウン切替方式)」を実装してください。

## 実行前タスク

以下のファイルを Read し、実装前のコンテキストを把握してください:

1. `docs/dev/dev_mas-115_unified_financial_statements.md` — 本仕様書全体
2. `600_report/602_datamart_main.js` — `buildBudgetTrendDataMart(overrideBoundary)` の構造(L159-L380)。`dmIngestData_` / `dmProcessAllEvents_` / `dmBuildPlOutput_` / `dmBuildBsOutput_` / `dmBuildCfOutput_` / `dmApplyDwhFormat_` の呼び出し順序を確認
3. `600_report/603_datamart_pl.js` — `dmBuildPlOutput_` の引数と戻り値(`{outM, outY, fmtM, fmtY, yoyColCount}`)、`isActualOnly`(L204)および `filterValues` / `filterWithRecalcTotal` の実装
4. `600_report/604_datamart_bs.js` — `dmBuildBsOutput_` の実装、`isActualOnly`(L148)
5. `600_report/605_datamart_cf.js` — `dmBuildCfOutput_` の実装、`isActualOnly`(L57)
6. `100_config/101_sys_config.js` — `onEdit`(L363-413)の既存分岐構造、`setupAllSchemas` と `SYS_CONFIG` への KEY 登録ロジック(L609-620 付近)、`onOpen`(L299-307)のメニュー構造
7. `300_ui/301_ui_assist.js` — `handleUxAssist(e)` が `onEdit` 内 L412 から呼ばれていることを確認
8. `200_data/202_repository.js` — `OrderRepository` / `InvoiceRepository` / `BankTxRepository` / `JournalRepository` / `AccountRepository` のみ存在し、**`BudgetRepository` は未実装**であることを確認
9. `templates/operations_sidebar.html` — サイドバーの `§📊 マート更新` セクションへのボタン追加箇所を確認
10. `CLAUDE.md` — DDL 管理外タブ一覧、コーディング規約
11. `docs/dev/dev_mas-094_boundary_month_selector.md` — MAS-094 のダイアログ方式の実装、将来プルダウン化時の共存方針

## 修正対象ファイル

- **新規作成**: `600_report/611_datamart_unified.js`
- **既存への追記**:
  - `600_report/602_datamart_main.js` — `buildBudgetTrendDataMart` を 3 関数に分割(`buildActualCtx_` / `buildPlanCtx_` / `writeToSheets_`)し、既存ラッパーとして維持
  - `100_config/101_sys_config.js` — `onEdit` に MAS-115 分岐ブロック追加、`setupAllSchemas` の KEY 登録に `FS_PL_U` / `FS_BS_U` / `FS_CF_U` の 3 行追加、DDL スキーマ定義(該当がある場合のみ)
  - `templates/operations_sidebar.html` — 統合タブ初期化ボタン 1 つ追加

## 実装内容

### Step 1: 統合シートの作成と初期化

1. 新規シート `60_fs_pl_unified` / `70_fs_bs_unified` / `80_fs_cf_unified` を導入。シート番号が既存 DDL スキーマと衝突しないことを `101_sys_config.js` の `setupAllSchemas` 内スキーマ一覧で確認してから確定する
2. `SYS_CONFIG` (`03_sys_params` テーブル)に KEY `FS_PL_U` / `FS_BS_U` / `FS_CF_U` を追加(101 L609-620 のパターンに準拠)
3. 各シートの A1 セルにデータバリデーション(プルダウン)を設置:
   - P/L: `実績・単月` / `実績・累積` / `計画含む・単月` / `計画含む・累積`
   - B/S: `実績` / `スナップショット(月末時点)` / `計画含む`
   - CF: `実績・単月` / `実績・累積` / `計画含む・単月` / `計画含む・累積`
4. プルダウン未選択時(A1 が空)のデフォルトは P/L・CF は `実績・単月`、B/S は `実績` とする

### Step 2: `onEdit` トリガーへの分岐追加

1. `100_config/101_sys_config.js` L363 の `onEdit(e)` 関数内、`Constants.CONFIG_SHEET` 分岐(L366-370)の**後**、`36_wrk_bank_import` 分岐(L372)の**前**に以下を挿入:

    if (sheetName === '60_fs_pl_unified' || sheetName === '70_fs_bs_unified' || sheetName === '80_fs_cf_unified') {
      if (e.range.getA1Notation() === 'A1') {
        try { handleUnifiedFsEdit_(e); } catch (err) { Utils.logError('handleUnifiedFsEdit_', err); }
        return;
      }
    }

2. L365 の `if (row === 1) return;` より**前**に上記ブロックを配置することで、1 行目の編集でも処理される分岐を確保する

### Step 3: 再描画ロジックの実装(`600_report/611_datamart_unified.js`)

1. `handleUnifiedFsEdit_(e)` — `LockService.getScriptLock()` + `tryLock(3000)` + `try/finally releaseLock()` パターンで排他制御。`sheetName` で P/L / B/S / CF を分岐し、プルダウン値(`e.value`)を `{ isActualOnly: boolean, viewMode: string }` のオブジェクトに変換して `renderUnified*_` を呼ぶ
2. `renderUnifiedPl_(mode)` — `buildActualCtx_()` または `buildPlanCtx_()` を呼んで ctx を構築し、`dmBuildPlOutput_(ctx)` で出力配列を取得、`mode.viewMode === 'ytd'` なら `outY`、それ以外は `outM` を選んで `dmApplyDwhFormat_(sheet, out, fmt, 'PL', targetMonthsWithActBgt)` で統合シートに書き出す
3. `renderUnifiedBs_(mode)` — 同上の流れで `dmBuildBsOutput_` → `outB` を書き出し。`mode.viewMode === 'snap'` のときは `dmRenderBsSnapshot_` 相当の処理を統合シート向けに呼ぶ
4. `renderUnifiedCf_(mode)` — 同上の流れで `dmBuildCfOutput_` → `outC` / `outCY` を書き出し
5. `ensureUnifiedSheetDropdown_(sheet, choices)` — A1 セルにプルダウンを冪等に設置するヘルパー
6. `buildBudgetTrendDataMart` を 3 関数(`buildActualCtx_` / `buildPlanCtx_` / `writeToSheets_`)に分割。既存の呼び出し側(`buildBudgetTrendDataMart()` / `buildDataMartWithCustomBoundary()`)は引数なし呼び出しを維持し、内部的に分割後関数を順に呼ぶラッパー構造とする
7. `Utils.toastResult('unifiedFs', '更新中...')` → 再描画 → `SpreadsheetApp.flush()` → `Utils.toastResult('unifiedFs', '完了')` の順で UX フィードバック

## 制約

- 既存の `onEdit` 分岐ロジックを破壊しないこと(特に L365 の `row === 1` 早期リターンの挙動は他分岐に影響しない形で回避する)
- 列番号のハードコード禁止。ヘッダー名 `indexOf` で参照(CLAUDE.md 規約)
- `BudgetRepository` が未存在のため、`41_trn_budget` への直接アクセスは本案件では行わない。既存 `dmIngestData_` / `dmIngestPlanData_` / `dmIngestPipelinePlanData_` 経由で得た `ctx` を再利用する
- 動作未確認のコードを GitHub に push しない(CLAUDE.md 規約)
- 実在しないメニュー名・関数名を動作確認手順に記載しない
- 既存 `61〜65 / 71〜73 / 81〜82b` の旧タブへの出力は並行稼働期間中は継続する(本案件では削除しない)

## エッジケース

| # | 条件 | 表示値/挙動 | 理由 |
|---|------|------------|------|
| E01 | プルダウン未選択(A1 セルが空) | デフォルト `実績・単月` で描画 | 初回アクセス時の UX |
| E02 | `42_trn_journal` / `41_trn_budget` が空 | エラーなく空の表を描画 | データ未投入時の安全な初期表示 |
| E03 | P/L 売上高=0(ゼロ除算) | `"-"` 表示 | failure_patterns.md #2 |
| E04 | `onEdit` 多重実行 | `tryLock(3000)` 失敗で `Utils.toastResult` 通知してスキップ | パフォーマンス保護 |
| E05 | MAS-094 / MAS-115 の同一 `onEdit` 発火 | `e.range.getA1Notation()` と `sheetName` で分岐 | MAS-094 との共存 |
| E06 | 旧関数呼び出し残存 | デプロイ前に `grep` で全参照確認 | failure_patterns.md #7 |
| E07 | 統合シート未作成でプルダウン操作 | `getSheetByKey` null → 早期 return | 未セットアップ環境での安全フェイル |
| E08 | `setupAllSchemas` でプルダウン消失 | DDL 側で `dataValidation` 再設定または毎マート更新で冪等設置 | DDL との整合性 |
| E09 | `boundaryMonthStr` 未確定(`1900-01`) | 既存 L237 の挙動継承 | 既存仕様継承 |
| E10 | 選択肢外の文字列が A1 に書き込まれる | バリデーションで拒否。通過時はデフォルトにフォールバック | 異常入力の安全処理 |
| E11 | B/S スナップで実績月なし | 空白表示 | 既存 72 挙動継承 |
| E12 | `flush()` 重複 | 冪等で安全 | パフォーマンス |
| E13 | プルダウン操作とマート更新同時 | `LockService` 競合で失敗 → 再操作依頼 | 二重書き込み防止 |
| E14 | 統合シート番号が将来予約 | 実装着手時にスキーマ一覧で再確認 | 番号衝突防止 |
| E15 | `handleUnifiedFsEdit_` 内例外 | `try/catch` で `Utils.logError` + alert、`finally` で `releaseLock` | 安全なエラーハンドリング |

## 実データ検証

- V01: 現行の `61_pl_monthly` / `62_pl_ytd` / `71_bs` / `81_cf_indirect` に実データがあることを dev 環境で確認
- V02: プルダウン選択肢文字列の UX ワーディングを確定
- V03: `isActualOnly` の型が boolean であることを 602 L243 で確認済
- V04: `41_trn_budget` に対象月のデータが存在することを確認
- V05: 統合タブ番号 60/70/80 が既存・計画中スキーマと衝突しないことを `grep` で確認
- V06: `LockService.tryLock(3000)` の挙動を手動検証
- V07: `setupAllSchemas` 再実行でプルダウンが消えないことを目視検証

## 動作確認

`npm run push:dev` 後、以下を確認:

1. スプレッドシートをリロードし、`🚀 BizLP` → 操作パネル(サイドバー)→ `📊 マート更新` セクションに「統合タブを初期化」ボタンが表示されること
2. 「統合タブを初期化」クリック → `60_fs_pl_unified` / `70_fs_bs_unified` / `80_fs_cf_unified` の 3 シートが生成され、A1 にプルダウンが設置されていること
3. P/L 統合タブの A1 を `実績・単月` に変更 → 61 タブと同じ内容が表示されること(境界月以降空白、実績のみ)
4. P/L 統合タブの A1 を `計画含む・累積` に変更 → 64 タブと同じ内容が表示されること
5. B/S 統合タブの A1 を `スナップショット(月末時点)` に変更 → 72 タブと同じ内容が表示されること
6. CF 統合タブの A1 を `実績・累積` に変更 → 81b タブと同じ内容が表示されること
7. プルダウン操作中に `buildBudgetTrendDataMart` を実行 → `LockService` 競合で片方がトースト通知してスキップされること
8. `setupAllSchemas` 実行 → 統合タブのプルダウンが消失しないこと

推奨実行モデル

工程推奨モデル理由
統合シート初期化・プルダウン設置(Step 1)Claude Sonnet 4.6setupAllSchemas 既存パターンへの追加、シート番号衝突確認の判断が必要(Haiku では判断不足)
onEdit 分岐追加・LockService 実装(Step 2)Claude Sonnet 4.6既存コードへの挿入位置特定(L365 の row === 1 回避方針の判断)、LockService パターンの適用
再描画ロジック全体・マートビルダ統合(Step 3)Claude Opus 4.6buildBudgetTrendDataMart の 3 関数分割リファクタ、実績 ctx / 計画 ctx の isActualOnlyviewMode マトリクス、複数ファイル横断の整合性確保
動作確認ユーザー手動GAS エディタでのメニュー操作・プルダウン操作・スプレッドシート目視確認が必要

変更履歴

日付変更内容
2026-04-19初版作成

仕様書作成プロンプト(再現性・監査性のため必ず記録)

展開して表示

【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】

  1. 拡張思考の使い分け: Phase 1(設計)では拡張思考をフル活用し、ファイル名・関数名・シート名・行番号・エッジケース一覧・Step 分割粒度を完全に確定させる。Phase 2(清書)の各 Step 内では拡張思考を最小限に抑え、Phase 1 で確定済みの内容の書き下しに徹する。出力途中で再考しない。
  2. テキスト報告の禁止: 「〜を作成します」等の text のみで tool_use なしに turn を終了しない。説明は 1 文以内。直ちに tool を呼ぶ。
  3. 4-5 分割の Write/Edit 実行: 仕様書作成は以下の Step に分けて実行する:
    • 2-1 骨格 Write(~20 行)
    • 2-2 概要〜注意事項 Edit/Bash(~300 行)
    • 2-3a エッジケース〜人間検討事項 Edit/Bash(~200 行)
    • 2-3b 実装プロンプト〜変更履歴 Edit/Bash(~250 行)
    • 2-4 <details> にプロンプト全文記録 Edit/Bash(最重量・必ず独立 Step)
  4. 各 Step で何を書くかを具体指示: 設計判断を Phase 2 実行時に持ち込まないよう、各 Step の内容を Phase 1 で箇条書きとして完全に確定させてから執筆に入る。

====================================================================== あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。 案件 MAS-115「財務諸表タブの統合(プルダウン切替方式)」の開発仕様書を作成してください。 作成後は docs/_config.jsonnav 配列の適切なセクションに必ず追記してください。


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

以下をすべて Read/Grep で調査し、Phase 2 着手前に設計内容を完全に確定させる。

1-A: 案件要件の把握

  • docs/_internal/TODO_future.md — MAS-115 の案件名・概要・期待効果・人間が検討すべき事項を正確に取得する。統合対象シート(P/L・B/S・CF)と対象外シートの範囲、プルダウン選択肢の候補を把握する。

1-B: プロジェクト規約の確認

  • CLAUDE.md — ブランチ運用・ファイル番号体系・DDL 管理外タブ一覧(91_fs_bs92_fs_pl93_kpi_dashboard 等)・コーディング規約(列参照はヘッダー名ベース、列 A のチェックボックス回避など)を確認する。

1-C: 既存財務諸表レポートの実装調査

600_report/ 配下の以下のファイルを Read し、実際の関数名・引数・シート書き込みロジックを確認する(Gemini 指示中の dmBuildPlMonthly_ 等は仮称のため、必ず Read で実在する関数名を裏取りすること):

  • 600_report/601_datamart_ingest.js
  • 600_report/602_datamart_pl.js
  • 600_report/603_datamart_bs.js
  • 600_report/604_datamart_cf.js
  • 600_report/605_datamart_kpi.js608_datamart_render.js(存在するファイルのみ)
  • 調査で確認すべき点:
    • P/L・B/S・CF のレポートシート名(61_pl_monthly 等)の実際の名称
    • isActualOnly フラグが定義・参照されているファイルと実際の型(boolean か文字列か)
    • 再描画関数の実シグネチャ(引数に表示モードを渡せる構造か否か)
    • SpreadsheetApp.flush() の既存使用箇所

1-D: onEdit トリガーの実装場所確認

  • 300_ui/301_ui_assist.js — 既存 onEdit 関数の構造・分岐パターン(e.range.getA1Notation() による分岐等)を Read する。MAS-115 用の分岐を追加する場合の挿入位置を確定する。

1-E: システム設定・初期化フローの確認

  • 100_config/101_sys_config.jsonOpen() のメニュー定義(実在するメニュー名の文字列を確認)・setupAllSchemas のシートキー登録ロジック・既存シートの番号帯を確認する。統合シートの番号(6X_ 帯)が既存と重複しないかを確認する。

1-F: MAS-094 との連携確認

  • docs/dev/dev_mas-094_boundary_month_selector.md — 基準年月プルダウンの実装方式を把握する。MAS-115 の表示モードプルダウンと同一 onEdit で共存できる設計を検討する。

1-G: データアクセス層の確認(ハルシネーション防止)

  • 200_data/202_repository.jsBudgetRepository が存在するかを Read で確認する。現時点では存在が未確認のため、存在しない場合は 41_trn_budget への直接アクセスパターン(getDataRange().getValues() + ヘッダー名ベース参照)を採用する方針を仕様書に明記すること。存在する Repository クラスは OrderRepositoryInvoiceRepositoryBankTxRepositoryJournalRepositoryAccountRepository であることは確認済み。
  • 000_infra/003_contracts.jsBudgetDTO の型定義(フィールド名)を確認する。

1-H: 参考仕様書の読み込み

  • docs/dev/dev_mas-093_cf_actual_only.md または docs/dev/dev_mas-001_variance_analysis.md — 財務諸表系仕様書のフォーマット・エッジケース記述の深度を把握する。

【Grep vs Read 原則】 シート名・関数名・定数名・メニュー名はすべて Read で実在を確認してから仕様書に記載する。名前や記憶から「〜だろう」と推測した瞬間に手を止めて Read する。


Phase 2: 仕様書の分割作成

出力先: docs/dev/dev_mas-115_unified_financial_statements.md (ファイル名は大文字 MAS-115 で統一すること)

Step 2-1: 骨格の作成(Write, ~20 行)

以下の見出しのみ(本文空で可)を Write で出力する:

# MAS-115: 財務諸表タブの統合(プルダウン切替方式)
## 概要
## 目的
## 現在のコード
## 修正方針
## 影響範囲
## 注意事項
## エッジケース
## 実データ検証
## 関連ドキュメント
## 人間が検討すべき事項
## 実装プロンプト(Claude Code 用)
## 推奨実行モデル
## 変更履歴
## 仕様書作成プロンプト(再現性・監査性のため必ず記録)

Step 2-2: 前半セクションの追記(Edit または Bash, ~300 行)

概要注意事項 に以下の内容を反映する。Phase 1 で確認した実際の関数名・シート名・行番号のみを記載し、未確認の固有名詞は「要調査」と明示する。

概要テーブル: 案件ID=MAS-115 / カテゴリ=財務諸表 UI 改善 / Phase・優先度・所要時間・対象ファイル(Phase 1 で特定したもの)/ 前提案件=MAS-094

目的: 現状 P/L・B/S・CF が別タブに分散している課題と、プルダウン切替方式による一本化の狙い(1〜3 文)

現在のコード: Phase 1 で特定した既存財務諸表シート名・レポートビルダ関数名・行番号を明記。対象シートが DDL 管理外(CLAUDE.md 記載の動的生成タブ)か否かも記載する。

修正方針(Step 分割形式):

  • Step 1: 統合シートの作成と初期化
    • 新規シート名と番号は Phase 1 で確認した番号帯の空きに基づいて決定する(番号帯が未確定の場合は「要確認」と仮記載)
    • A1 セルへのデータバリデーション(プルダウン)設置。選択肢文字列は Phase 1 の TODO_future.md 調査結果から決定。なお列 A のチェックボックス規約は データ入力シートに適用される規約であり、財務諸表レポートシートでは適用外であることを注記する
    • setupAllSchemas または onOpen 時の初期化処理への組み込み方針(100_config/101_sys_config.js の既存パターンに準拠)
  • Step 2: onEdit トリガーへの分岐追加
    • 配置先: 300_ui/301_ui_assist.js 内の既存 onEdit 関数(Phase 1 で確認した実際の構造に基づき挿入位置を特定)
    • e.range.getA1Notation() で変更セルを判定し、MAS-094 の基準年月プルダウンと共存できる分岐を設計
    • LockService.getScriptLock() による排他制御: tryLock(3000) でロック取得 → 取得失敗時は Utils.toastResult() 通知して中断 → finally ブロックで lock.releaseLock() を確実に実行
  • Step 3: 再描画ロジックの実装
    • Phase 1 で確認した既存マートビルダ関数(実関数名を明記)を再利用。表示モードを引数オブジェクトで渡すリファクタリングが必要か否かを Phase 1 調査結果に基づいて判断する
    • isActualOnly フラグとの整合性: Phase 1 で確認した実際の型・参照箇所に基づいて記述
    • 処理中表示: Utils.toastResult(funcName, '更新中...') → 完了時に再度 Utils.toastResult() で通知
    • 大量書き込みがある場合は SpreadsheetApp.flush() を適切に挿入

影響範囲: 変更ファイルリスト(Phase 1 で確定)・既存財務諸表シートへの参照影響・setupAllSchemas への追加の有無

注意事項(番号付きリスト):

  1. BudgetRepository202_repository.js に存在しない場合は予算データへの直接アクセス方式(41_trn_budgetgetDataRange().getValues() + ヘッダー名ベース参照)を採用すること。Phase 1 調査で存在が確認された場合のみ Repository 経由に変更する
  2. 既存 onEdit 分岐ロジックへの追記時は、既存の getA1Notation() による条件分岐を破壊しないこと
  3. 統合シートが DDL 管理外タブ(動的生成)の場合、setupAllSchemas 実行で上書きされないよう注意
  4. CLAUDE.md コーディング規約: 列参照はヘッダー名ベース(indexOf)、列番号ハードコード禁止、有効フラグ=FALSE の行スキップを遵守
  5. 移行期間中は旧タブと統合タブを並行稼働させるため、旧タブの既存レポートビルダ関数への影響が出ないようにすること

Step 2-3a: エッジケース〜人間検討事項の追記(Edit または Bash, ~200 行)

エッジケーステーブル(テーブル形式: 条件 | 表示値/挙動 | 理由):

条件表示値/挙動理由
プルダウン未選択時デフォルトモード(実績単月等)で描画初回アクセス時の UX
仕訳・予算データが空エラーなく空の表を描画(列ヘッダー維持)データなし時の安全な描画
P/L 比率計算で売上=0(ゼロ除算)"-" 表示(failure_patterns.md #2 に準拠)ゼロ除算のフォールバック
onEdit の多重実行LockService でスキップ、Utils.toastResult() 通知パフォーマンス保護
MAS-094 プルダウンと MAS-115 プルダウンが同一 onEdit で発火e.range.getA1Notation() で分岐し、両方の値を参照して再描画MAS-094 との共存
既存マートビルダ関数のリファクタリング中に旧関数呼び出しが残存デプロイ前に grep で旧関数名の全参照を確認(failure_patterns.md #7 に準拠)分割時の未定義関数防止

実データ検証(実装前に MCP 等で確認すべき項目):

  • 現行の 61_pl_monthly 等に実データがある状態で既存表示が統合後も壊れないこと
  • プルダウン選択肢の文字列(DDL 定義のコード値 vs シートに実際に格納されている値の乖離)
  • isActualOnly の実際の格納型(boolean か文字列 "TRUE"/"FALSE" か)
  • 41_trn_budget に対象月のデータが存在するか(予算ゼロ月の動作確認)

関連ドキュメントテーブル(仕様書リンク | 関連箇所):

  • MAS-094 仕様書 / 基準年月プルダウンの onEdit 実装
  • dev_mas-093_cf_actual_only.md / isActualOnly 分岐ロジック
  • docs/_internal/failure_patterns.md #2 / ゼロ除算フォールバック
  • docs/_internal/failure_patterns.md #7 / ファイル分割時の旧関数残存

人間が検討すべき事項(TODO_future.md から転記 + 以下の追加事項):

  • プルダウン選択肢の確定(表示モード名・選択肢数は要件定義が必要)
  • 統合シートの番号帯・シート名の最終確定(既存番号帯との重複確認)
  • BudgetRepository の設計判断(新規 Repository クラス作成 vs 41_trn_budget 直接アクセス)
  • 移行計画: 新旧タブの並行稼働期間(推奨 1 ヶ月)・旧タブの段階的廃止ステップ(旧タブ上部に移行案内 → 非表示化 → 安定確認後削除)
  • 旧タブの廃止タイミングで関連する既存テストケース(901_test_runner.js)の更新要否

Step 2-3b: 実装プロンプト〜変更履歴の追記(Edit または Bash, ~250 行)

【必須フォーマット規則】実装プロンプトはバッククォートのコードブロックで囲まず、全行を行頭 4 スペースインデントで出力すること。

実装プロンプトには以下を自己完結形式で含める:

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-115「財務諸表タブの統合(プルダウン切替方式)」を実装してください。

## 実行前タスク
(Phase 1 で列挙したファイルリストと、各ファイルで確認すべきポイントを明記)

## 修正対象ファイル
(Phase 1 で確定したファイル名のみ。「のみ」または「への追記」を明示)

## 実装内容
(Step 1〜3 の具体的な変更手順。関数名・行番号は Phase 1 で裏取り済みのもののみ記載)

## 制約
- 既存 onEdit 分岐ロジックを破壊しないこと
- 列番号のハードコード禁止(ヘッダー名 indexOf で参照)
- BudgetRepository が未存在の場合は 41_trn_budget を直接参照する方式を採用
- 動作未確認のコードを GitHub に push しない(CLAUDE.md 規約)
- 実在しないメニュー名・関数名を動作確認手順に記載しないこと

## エッジケース
(Step 2-3a のテーブルを転記)

## 実データ検証
(Step 2-3a の実データ検証項目を転記)

## 動作確認
(npm run push:dev 後の検証手順。メニュー名は Phase 1 で onOpen を Read して確認した実在の文字列のみ使用)

推奨実行モデルテーブル(工程 | 推奨モデル | 理由):

工程推奨モデル理由
統合シート初期化・プルダウン設置(Step 1)Claude Haiku 4.5コードが完全定義済み・判断要素なし
onEdit 分岐追加・LockService 実装(Step 2)Claude Sonnet 4.6既存コードへの挿入位置の特定が必要
再描画ロジック全体・マートビルダ統合(Step 3)Claude Opus 4.6複数ファイル横断・会計ロジック理解が必要

変更履歴テーブル: | 2026-04-19 | 初版作成 |

Step 2-4: 仕様書作成プロンプトの記録(Edit または Bash, 最重量・必ず独立 Step)

仕様書末尾の ## 仕様書作成プロンプト(再現性・監査性のため必ず記録) セクションに、この <instruction> 全文を以下の形式で追記する:

<details><summary>展開して表示</summary>
(この instruction 全文をそのまま貼り付ける)
</details>

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

3-A: _config.json への登録(必須)

docs/_config.json§E.4 データマート・財務諸表 セクションに以下を追加し、追加後に JSON 構文が正しいことを確認する:

{ "file": "dev/dev_mas-115_unified_financial_statements.md", "title": "E.4.X S-43 財務諸表タブの統合(プルダウン切替方式)" }

E.4.X の連番は既存エントリを確認して採番すること)

3-B: changelog への追記

docs/_internal/changelog.md のヘッダー直後に以下を追記する:

| 2026-04-19 | [dev_mas-115_unified_financial_statements.md](dev_mas-115_unified_financial_statements.md) | 初版作成。財務諸表タブ統合(プルダウン切替方式)の開発仕様書 |

3-C: コミット&プッシュ

git add docs/dev/dev_mas-115_unified_financial_statements.md docs/_internal/changelog.md docs/_config.json
git commit -m "docs: S-43 財務諸表タブの統合(プルダウン切替方式)の開発仕様書を作成

P/L・B/S・CFタブをプルダウン切替方式で統合する仕様書の初版。
onEditトリガー・LockService排他制御・S-22連携・BudgetRepository要調査事項を設計。

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