概要

項目内容
案件IDMAS-094
カテゴリデータマート
PhaseP2
優先度★★
所要時間2時間
対象ファイル600_report/602_datamart_main.js, 100_config/101_sys_config.js(メニュー追加)
前提案件なし(独立着手可能)

目的

マート更新時に実績集計の基準年月(境界月)をユーザーが選択できるようにし、月次締め前の仮集計や過去月の実績確認を可能にする。現在は boundaryMonthStr が自動計算(max実績月の翌月)で固定されており、任意月での実績確認ができない。

現在のコード

boundaryMonthStr の自動計算(601_datamart_ingest.js L251-256)

const today = new Date();
const currentYmStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`;
let boundaryMonthStr = hasInvData && maxInvYm !== '1900-01'
  ? Utils.addMonths(maxInvYm, 1) : currentYmStr;
if (boundaryMonthStr > currentYmStr) boundaryMonthStr = currentYmStr;

buildBudgetTrendDataMart の関数シグネチャ(602_datamart_main.js L157)

function buildBudgetTrendDataMart() {   // ← 引数なし

boundaryMonthStr の上書き挿入ポイント(602_datamart_main.js L211)

dmIngestData_(ctx, sheetInv, sheetBank, sheetAcct);
// ★ この直後に overrideBoundary の反映を挿入する

// 1b. 32タブの諸表区分・表示区分を科目マスタから同期
dmSyncInvClassification_(ctx.acctMap, sheetInv);

boundaryMonthStr の使用箇所

ファイル用途
602_datamart_main.jsL229-234uiHeader の「実績反映: YYYY-MM まで」表示、targetMonthsWithActBgt 生成
602_datamart_main.jsL252計画パイプラインの planCtx への引き継ぎ
603_datamart_pl.js各所isActualOnly 時の filterValues / filterWithRecalcTotal
604_datamart_bs.js各所B/S の filterBsValues
605_datamart_cf.js各所C/F の filterValues

既存のメニュー構造(101_sys_config.js L328-331)

ui.createMenu('📊 マート更新')
  .addItem('財務3表(P/L・B/S・C/F)の更新', 'buildBudgetTrendDataMart')
  .addItem('プロジェクト別 採算(限界利益)の生成', 'buildProjectProfitability')
  .addToUi();

修正方針

実装方式: ダイアログ方式

マート更新メニューに「基準年月を指定して更新」を追加。実行時にダイアログで基準月を入力し、buildBudgetTrendDataMart にオプション引数として渡す。

この方式を選んだ理由:

方式評価理由
03_sys_params パラメータ毎回シートを開いて値を変更する手間。戻し忘れリスク
ダイアログ (prompt)1回のメニュー操作で完結。一時的な上書きで戻し忘れなし
実績タブにプルダウンプルダウン値変更後に再計算が必要。トリガーの仕組みが複雑

Step 1: buildBudgetTrendDataMart() への引数追加

602_datamart_main.js L157 の関数シグネチャにオプション引数を追加し、L211(dmIngestData_ 直後)に上書きロジックを挿入する。

// L157: 関数シグネチャ変更
function buildBudgetTrendDataMart(overrideBoundary) {

// L211-214: dmIngestData_ 直後に挿入
    dmIngestData_(ctx, sheetInv, sheetBank, sheetAcct);

    // S-22: 基準年月の手動上書き
    if (overrideBoundary) {
      ctx.boundaryMonthStr = overrideBoundary;
      Utils.logInfo(FUNC, '基準年月を手動指定: ' + overrideBoundary);
    }

    // 1b. 32タブの諸表区分・表示区分を科目マスタから同期
    dmSyncInvClassification_(ctx.acctMap, sheetInv);

Step 2: buildDataMartWithCustomBoundary() ラッパー関数の追加

602_datamart_main.js の末尾(buildBudgetTrendDataMart 関数の外側)に追加。

/**
 * S-22: 基準年月を指定して財務3表を更新する
 * ユーザーに基準年月をpromptで入力させ、buildBudgetTrendDataMart に渡す
 */
function buildDataMartWithCustomBoundary() {
  var ui = SpreadsheetApp.getUi();
  // 選択肢の構築: 今期の12ヶ月
  var today = new Date();
  var startYear = (today.getMonth() + 1 >= 8) ? today.getFullYear() : today.getFullYear() - 1;
  var choices = [];
  for (var i = 0; i < 12; i++) {
    var d = new Date(startYear, 7 + i, 1);
    choices.push(d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0'));
  }

  var result = ui.prompt(
    '📅 基準年月の選択',
    '実績集計の末月を指定してください。\n'
      + '指定月までが実績、翌月以降が予算として表示されます。\n\n'
      + '選択肢:\n' + choices.join('\n') + '\n\n'
      + '入力例: 2025-12\n(空欄で自動計算)',
    ui.ButtonSet.OK_CANCEL
  );

  if (result.getSelectedButton() !== ui.Button.OK) return;

  var input = result.getResponseText().trim();
  if (!input) {
    buildBudgetTrendDataMart();  // 通常実行
  } else {
    var ym = Utils.parseDateToYm(input);
    if (!ym) {
      ui.alert('⚠️ 入力形式エラー', '「YYYY-MM」形式で入力してください。', ui.ButtonSet.OK);
      return;
    }
    // 入力月 = 実績最終月 → 翌月を境界月として設定
    buildBudgetTrendDataMart(Utils.addMonths(ym, 1));
  }
}

Step 3: メニューへの追加

101_sys_config.js L328-331 のメニュー構築に1行追加。

ui.createMenu('📊 マート更新')
  .addItem('財務3表(P/L・B/S・C/F)の更新', 'buildBudgetTrendDataMart')
  .addItem('📅 基準年月を指定して更新', 'buildDataMartWithCustomBoundary')  // S-22
  .addItem('プロジェクト別 採算(限界利益)の生成', 'buildProjectProfitability')
  .addToUi();

影響範囲

変更対象変更内容変更量
600_report/602_datamart_main.js引数追加(1行) + 上書きロジック(4行) + ラッパー関数(~35行)~40行
100_config/101_sys_config.jsメニュー項目1行追加1行
  • 既存動作への影響: buildBudgetTrendDataMart() を引数なしで呼んだ場合は完全に従来通り。引数はオプション
  • 下流への波及: ctx.boundaryMonthStr の上書きにより、filterValues / filterWithRecalcTotal / uiHeader / targetMonthsWithActBgt が全て連動して変わる。603/604/605 の変更は不要

注意事項

  1. 上書きは一時的: ダイアログで指定した基準月は今回の実行にのみ適用。次回の通常実行(引数なし)では自動計算に戻る
  2. 未来月の制限: dmIngestData_ 内の if (boundaryMonthStr > currentYmStr) クランプは維持。上書きはその後なので、未来月を指定しても実績データが存在しない月が含まれうる。ただしデータがない月は金額0になるだけで壊れない
  3. 過去月の指定: 問題なし。指定月以降は予算扱いになるだけ
  4. 計画タブ(63/64): planCtx.boundaryMonthStr = ctx.boundaryMonthStr(L252)で計画にも波及する。意図通りの動作
  5. 上書き挿入位置: dmIngestData_ の直後かつ dmSyncInvClassification_ の前に挿入。dmIngestData_ で自動計算された boundaryMonthStr を上書きする

エッジケース

条件動作理由
空欄で OK引数なしで通常実行(自動計算)ユーザーが「やっぱりデフォルトで」と思った場合の安全パス
キャンセル何も実行しないユーザー中断
不正な入力(例: "abc")Utils.parseDateToYm が空文字を返す → エラーダイアログパースエラーの安全な処理
今期外の月(例: "2024-01")正常に実行される。ただし当期の12ヶ月すべてが予算扱いになるboundaryMonthStr が期首より前になるだけ。壊れはしないが意味のある集計にならない
未来月の指定(例: "2026-08")翌月(2026-09)が境界月になる。601の自動計算より先の月を指定可能実績データがない月は金額0。P/L・B/S・CFの数値は0になるだけで構造的に壊れない
期首月を指定(例: "2025-08")8月のみ実績、9月以降予算正常動作。最小の実績範囲

実データ検証(MCP でのデータ確認が必要な場合)

確認項目確認方法理由
現在の boundaryMonthStr 自動計算値マート更新を実行し、61タブのヘッダー「実績反映: YYYY-MM まで」を確認上書き前のデフォルト値を把握し、テスト時の期待値を決定するため
実績データの存在月範囲32_wrk_invoice の 発生日(P/L計上日) のmin/max を確認指定可能な実績月の範囲を把握

関連ドキュメント

仕様書関連箇所
CLAUDE.md変更時の動作確認テスト: 600_report/6*_datamart_*.js → マート更新テスト
601_datamart_ingest.jsL251-256: boundaryMonthStr 自動計算ロジック(変更しない)

人間が検討すべき事項

  • プルダウンの配置場所: 本仕様ではダイアログ方式を採用(TODO_future.md から転記)
  • 未来月の指定を許可するか: 技術的には可能だが、実績データがない月は金額0になる。初版では制限せず、ユーザー判断に委ねる

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

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-094「実績集計の基準年月プルダウン選択」を実装してください。

## 実行前タスク
以下のファイルを読み込んでください:
1. `600_report/602_datamart_main.js` — `buildBudgetTrendDataMart()` の全体構造(L157)。`dmIngestData_()` 直後(L211)での ctx.boundaryMonthStr 設定箇所を確認
2. `600_report/601_datamart_ingest.js` — L251-256 の boundaryMonthStr 自動計算ロジック(変更しない。参照のみ)
3. `100_config/101_sys_config.js` — L328-331 の「📊 マート更新」メニュー構築箇所
4. `000_infra/004_utils.js` — `Utils.parseDateToYm()`(L92)と `Utils.addMonths()`(L127)のシグネチャ
5. `CLAUDE.md`
6. `docs/dev/dev_mas-094_boundary_month_selector.md`

## 修正対象ファイル
- `600_report/602_datamart_main.js` — 引数追加 + ラッパー関数追加
- `100_config/101_sys_config.js` — メニュー項目追加

## 実装内容

### A: buildBudgetTrendDataMart() への引数追加(602_datamart_main.js L157)
関数シグネチャを `function buildBudgetTrendDataMart(overrideBoundary)` に変更。
L211(`dmIngestData_(ctx, ...)` の直後、`dmSyncInvClassification_` の前)に以下を挿入:
```js
// S-22: 基準年月の手動上書き
if (overrideBoundary) {
  ctx.boundaryMonthStr = overrideBoundary;
  Utils.logInfo(FUNC, '基準年月を手動指定: ' + overrideBoundary);
}
```

### B: buildDataMartWithCustomBoundary() ラッパー関数の追加(602_datamart_main.js 末尾)
- `SpreadsheetApp.getUi().prompt()` でユーザーに基準年月を入力させる
- 今期の12ヶ月を選択肢として表示
- 入力値を `Utils.parseDateToYm()` でパースし、`Utils.addMonths(ym, 1)` で翌月を境界月に変換
- 空欄なら引数なしで通常実行、キャンセルなら何もしない

### C: メニュー追加(101_sys_config.js L328-331)
「📊 マート更新」メニューの「財務3表の更新」と「プロジェクト別」の間に追加:
`.addItem('📅 基準年月を指定して更新', 'buildDataMartWithCustomBoundary')`

## 制約
- 既存の `buildBudgetTrendDataMart()` を引数なしで呼んだ場合の動作は一切変えない
- `dmIngestData_()` 内の boundaryMonthStr 自動計算ロジック(601_datamart_ingest.js)は変更しない
- 603/604/605 のファイルは変更しない

## エッジケース
| 条件 | 動作 |
|------|------|
| 空欄で OK | 引数なしで通常実行 |
| キャンセル | 何も実行しない |
| 不正な入力 | エラーダイアログ表示 |
| 今期外の月 | 正常実行(全月が予算扱い) |

## 動作確認
`npm run push:dev` 後:
1. スプレッドシートをリロードし、「📊 マート更新」メニューに「📅 基準年月を指定して更新」が表示されること
2. メニュークリック → ダイアログが表示され、今期12ヶ月の選択肢が表示されること
3. 「2025-12」と入力 → OK → マート更新実行。61タブで2025-12月までが「(実績)」、2026-01以降が「(予算)」であること
4. 空欄で OK → 通常の自動計算と同じ結果になること
5. キャンセル → 何も実行されないこと
6. 「abc」と入力 → エラーダイアログが表示されること

### 拡張思考の使用状況

| フェーズ | 拡張思考 | 備考 |
|---------|:--------:|------|
| buildBudgetTrendDataMart 引数追加 | なし | 1行のシグネチャ変更 + 4行の条件分岐追加 |
| ラッパー関数実装 | なし | prompt → parseDateToYm → addMonths の単純なフロー |
| メニュー追加 | なし | addItem 1行追加 |

推奨実行モデル

工程推奨モデル理由
仕様書作成(本ドキュメント)Claude Opus 4.6boundaryMonthStr の全使用箇所の影響分析、実装方式の比較判断に高い推論力が必要
実装Claude Haiku 4.5仕様書でコードが完全に定義済み。引数追加 + ラッパー関数 + メニュー1行の機械的作業
動作確認ユーザー手動GASエディタでのメニュー操作とダイアログ入力が必要

変更履歴

日付変更内容
2026-04-14初版作成
2026-04-16テンプレート準拠で全面改訂。エッジケース・実データ検証セクション追加、行番号を最新コードに更新、実装プロンプトを4字インデントに変更