概要

項目内容
案件IDMAS-138
カテゴリパイプライン / 資金繰り予測
PhaseP1(Phase 2 で実装予定)
優先度★★
所要時間2〜3 時間
対象ファイル600_report/606_datamart_daily_cf.js(dmBuildPlanCashflow_ 改修)、200_data/202_repository.js(PipelineRepository 新規追加)、000_infra/003_contracts.js(PipelineDTO 新規追加)、000_infra/002_constants.js(PIPELINE_PROBABILITIES 新規追加)、100_config/101_sys_config.js(32_wrk_invoice に 親パイプラインID(PIP) 列追加 / 03_sys_params 既定値追加)
前提案件MAS-078(pipeline_cf_integration.md)— フック型設計の代替案として Repository + DTO を新設する
後続案件MAS-008(Cash Runway・84タブ入力元拡張後の指標再計算)、MAS-079(51タブ読み込み対応)

目的

84_cf_daily_plan は現状、32_wrk_invoice の確定 INV のみを入金予測ソースとしている。 受注前のパイプライン案件(21_bud_pipeline)は CF 予測に反映されておらず、「営業段階の見込み入金」が資金繰りから抜け落ちている。

本案件では 21_bud_pipeline シートを第 2 の入金予測ソースとして 84 タブへ合流させる。 確度(ヨミ)に基づく確率加重・最低確率フィルタ・マスターフラグにより、 「確定分 + 確度加重済み見込み分」のハイブリッド予測を実現し、MAS-008(Cash Runway)の精度を底上げする。

解決すべき中核課題

  1. 二重計上の完全防止: パイプラインが受注され 32_wrk_invoice に INV 起票された時点で、見込みと確定の両方が CF に積まれる事故を、親パイプラインID(PIP) による ID ベースの排他で根絶する。
  2. 確度加重のパラメータ化: 閾値(何% 以上を計画に含めるか)、重み付けの有無(金額×確率 か 100% 計上か)を 03_sys_params で運用切替可能にする。
  3. 結果の透明性: 84 タブに「データソース」列を追加し、どの行が実績-INV 由来か、計画-PIP 由来かを一目で判別できるようにする。

現在のコード

1. 日次 CF 生成のエントリ(600_report/606_datamart_daily_cf.js)

関数役割出力タブ
dmBuildDailyCashflow_実績日次 CF(33_wrk_bank 消込STL のみ)81_cf_daily_actual 等
dmBuildPlanCashflow_計画日次 CF(32_wrk_invoice 由来 + 実績ハイブリッド)84_cf_daily_plan

本仕様の改修対象は dmBuildPlanCashflow_。 既存の cashEvents 配列(32_wrk_invoice の決済予定のみを push)に、パイプライン由来のイベントを追加する設計とする。

2. cashEvents 要素の既存構造

cashEvents.push({
  date: dateStr,      // 'YYYY-MM-DD'
  src: '計画',         // 計画 / 計上 / 実績
  refId: invId,       // 例: 'INV_20260401_0001'
  acc: pm,            // 決済手段
  memo: memo + ' [INV:' + invId + ']',
  inAmt: isIn ? cfAmt : 0,
  outAmt: isIn ? 0 : cfAmt
});

3. 21_bud_pipeline の列構造(DDL 現状)

有効フラグ / 管理ID(PIP_ID) / PJ・案件名 / 契約形態 / 売上科目 /
確度(ヨミ) / 計上開始年月 / スポット売上・初期費用 / 継続月額(MRR) /
継続月数 / 取引先名 / 決済手段 / CF計上 / 入金ラグ(月) /
入金日 / 休日調整 / 組織名 / 起票ターゲット月 / 最終起票年月日 / 備考

4. 32_wrk_invoice の親 ID 列(現状)

  • 親発注ID(ORD) … 既存
  • 親パイプラインID(PIP)現在未定義(本仕様で DDL 追加)

5. 既存の再利用対象ユーティリティ

関数用途
Utils.parseDateToYmd(val)日付 → 'YYYY-MM-DD'
Utils.parseDateToYm(val)日付 → 'YYYY-MM'
Utils.addMonths(ymStr, months)'YYYY-MM' に月加減
Utils.adjustToBusinessDay(ymdStr, direction)祝日・週末の前後調整
Utils.parseAmt(val)金額パース
Contracts.toDto / Contracts.toDtoList / Contracts.toRows行⇔DTO 変換
Constants.getParam(key, defaultVal)03_sys_params 参照

修正方針

Step 1: 定数・DTO・Repository の新規追加

1-1. 000_infra/002_constants.jsPIPELINE_PROBABILITIES を追加

21_bud_pipeline.確度(ヨミ) の文字列を確率数値(0.0〜1.0)にマッピングするオブジェクトを Constants に追加する。 列挙値は Constants.SHEET_DEFAULTSBUD_PIPE エントリと一致させる。

// Constants 本体に追加
PIPELINE_PROBABILITIES: {
  'Sヨミ (確度95%)': 0.95,
  'Aヨミ (確度80%)': 0.80,
  'Bヨミ (確度50%)': 0.50,
  'Cヨミ (確度30%)': 0.30,
  'Dヨミ (確度10%)': 0.10,
  '失注': 0.0
}

正規化のため Constants.getPipelineProbability(label) ヘルパも併設し、未定義ラベルは null を返して「警告ログ + 計算除外」を呼び出し側で判定できるようにする。

1-2. 000_infra/003_contracts.jsPipelineDTO を追加

21_bud_pipeline のヘッダー順に沿った JSDoc @typedef を定義する。 Contracts.toDto 経由でシートヘッダー名とキー名がそのまま対応する前提(既存 InvoiceDTO と同様)。

/**
 * @typedef {Object} PipelineDTO
 * @property {boolean} 有効フラグ
 * @property {string}  管理ID
 * @property {string}  PJ・案件名
 * @property {string}  契約形態
 * @property {string}  売上科目
 * @property {string}  確度(ヨミ)
 * @property {string}  計上開始年月
 * @property {number}  スポット売上・初期費用
 * @property {number}  継続月額(MRR)
 * @property {number}  継続月数
 * @property {string}  取引先名
 * @property {string}  決済手段
 * @property {string}  CF計上
 * @property {number}  入金ラグ(月)
 * @property {number}  入金日
 * @property {string}  休日調整
 * @property {string}  組織名
 * @property {string}  起票ターゲット月
 * @property {string|Date} 最終起票年月日
 * @property {string}  備考
 */

1-3. 200_data/202_repository.jsPipelineRepository を追加

InvoiceRepository と同一パターンで実装(findAll / save / append)。 戻り値は { headers, dtos } 形式で統一する。

var PipelineRepository = {
  _getSheet: function() {
    return Utils.getSheetByKey('BUD_PIPE', '21_bud_pipeline');
  },
  findAll: function() {
    return readSheetAsDtos_(PipelineRepository._getSheet());
  },
  save: function(dtos) {
    var sheet = PipelineRepository._getSheet();
    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    writeDtosToSheet_(sheet, headers, dtos);
  },
  append: function(dtos) {
    var sheet = PipelineRepository._getSheet();
    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    return appendDtosToSheet_(sheet, headers, dtos, 0);
  }
};

Step 2: dmBuildPlanCashflow_ へのパイプライン合流ロジック追加

改修は 606_datamart_daily_cf.jsdmBuildPlanCashflow_ 内、cashEvents 構築ブロックの直後 に差し込む。

2-1. マスターフラグと制御パラメータの取得

const includePipeline       = String(Constants.getParam('CF_INCLUDE_PIPELINE', 'TRUE')).toUpperCase() === 'TRUE';
const minProbability        = Number(Constants.getParam('CF_PIPELINE_MIN_PROBABILITY', 0.8));
const useProbabilityWeight  = String(Constants.getParam('CF_PIPELINE_USE_WEIGHTING', 'TRUE')).toUpperCase() === 'TRUE';
if (!includePipeline || isActualOnly) {
  // 実績専用モード or マスター OFF の場合は合流スキップ
  return cashEvents;
}

2-2. 既起票 PIP_ID セットの構築(二重計上防止)

関数冒頭で 32_wrk_invoice を一度読むため、既存の invDtos をそのまま利用し、 親パイプラインID(PIP) が非空のものから Set を作る。

const processedPipIds = new Set();
invDtos.forEach(function(inv) {
  var pipId = inv['親パイプラインID(PIP)'];
  if (pipId && String(pipId).trim()) processedPipIds.add(String(pipId).trim());
});

2-3. パイプライン読み込みと入金予定レコードの生成

const pipResult = PipelineRepository.findAll();
const pipDtos   = pipResult.dtos.filter(function(p) {
  if (p['有効フラグ'] !== true) return false;
  if (processedPipIds.has(String(p['管理ID']).trim())) return false;
  if (String(p['CF計上']).trim() === 'FALSE') return false;
  return true;
});

const pipelineEvents = [];
const warnings = [];

pipDtos.forEach(function(p) {
  const prob = Constants.getPipelineProbability(p['確度(ヨミ)']);
  if (prob === null) { warnings.push('確度未定義: ' + p['管理ID'] + ' / ' + p['確度(ヨミ)']); return; }
  if (prob < minProbability) return;

  const weight    = useProbabilityWeight ? prob : 1.0;
  const startYm   = Utils.parseDateToYm(p['計上開始年月']);
  if (!startYm) { warnings.push('計上開始年月不正: ' + p['管理ID']); return; }

  const lag       = Number(p['入金ラグ(月)'] || 0);
  const payDay    = Number(p['入金日'] || 25);
  const adjustDir = p['休日調整'] || '前';
  const spot      = Number(p['スポット売上・初期費用'] || 0);
  const mrr       = Number(p['継続月額(MRR)'] || 0);
  const months    = Number(p['継続月数'] || 0);

  // 1) スポット売上・初期費用(初月)
  if (spot > 0) pipelineEvents.push(buildPipelineEvent_(p, startYm, lag, payDay, adjustDir, spot * weight, '初期'));
  // 2) MRR 継続月
  if (mrr > 0 && months > 0) {
    for (var m = 0; m < months; m++) {
      var ym = Utils.addMonths(startYm, m);
      pipelineEvents.push(buildPipelineEvent_(p, ym, lag, payDay, adjustDir, mrr * weight, 'MRR'));
    }
  }
});

// cashEvents に合流
Array.prototype.push.apply(cashEvents, pipelineEvents);

補助関数(モジュール内ローカル):

function buildPipelineEvent_(pip, ym, lag, day, dir, amt, kind) {
  const payYm  = Utils.addMonths(ym, lag);
  const ymd    = payYm + '-' + String(day).padStart(2, '0');
  const dateStr = Utils.adjustToBusinessDay(ymd, dir);
  return {
    date: dateStr,
    src:  '計画-PIP',
    refId: pip['管理ID'],
    acc:  pip['決済手段'] || '口座振込',
    memo: '[PIP:' + pip['管理ID'] + '] ' + pip['PJ・案件名'] + ' (' + kind + ', 確度=' + pip['確度(ヨミ)'] + ')',
    inAmt:  amt,
    outAmt: 0
  };
}

Step 3: 32_wrk_invoice の DDL 拡張と二重計上防止

3-1. スキーマ追加

100_config/101_sys_config.jssetupAllSchemasWRK_INVC ヘッダー配列に 親パイプラインID(PIP) を追加(位置は 親発注ID(ORD) の直後を推奨)。

3-2. 移行スクリプト

800_ops/ 配下に 809_migration_s06.js(既存マイグレーション連番の次)を新規配置し、以下を実施する。

  1. 既存の 32_wrk_invoice親パイプラインID(PIP) 列が存在しない場合、列を挿入。
  2. 冪等性チェック: 列が既に存在したらスキップ(CLAUDE.md のマイグレーション運用ルール準拠)。
  3. 101_sys_config.js の「🔧 マイグレーション」メニューに migrationS06() を登録。
  4. Utils.logInfoSpreadsheetApp.getUi().alert の両方でログ出力。

3-3. RPA 側の書き込み対応

400_domain/406_rpa_pipeline.js(パイプライン→INV 起票)で INV 生成時に、起票元 PIP_ID を 親パイプラインID(PIP) 列へ書き込む。 MAS-080 で早期採番された PIP_ID がここに入ることで、Step 2-2 の processedPipIds セットが正しく機能する。

Step 4: 03_sys_params への制御パラメータ追加・サマリー通知

4-1. 既定値の投入

setupAllSchemas03_sys_params 初期投入処理、または 809_migration_s06.js で以下キーを追加する(既存キーはスキップ = 冪等)。

キー既定値説明
CF_INCLUDE_PIPELINEBOOLEANTRUE84タブにパイプライン見込みを合流するマスターフラグ
CF_PIPELINE_MIN_PROBABILITYNUMBER0.8計画に含める最低確率(未満は無視)
CF_PIPELINE_USE_WEIGHTINGBOOLEANTRUETRUE=金額×確率で加重、FALSE=閾値超を100%計上

4-2. 84_cf_daily_plan のヘッダー拡張

データソース 列を追加し、各行の src 値(計画 / 計画-PIP / 実績)を書き込む。 既存のヘッダー出力処理(dmBuildPlanCashflow_ 内のシート書き出し部)に列を 1 本追加する。

4-3. 完了通知

dmBuildPlanCashflow_ の末尾で、パイプライン合流件数と加重後合計金額を集計し、 Utils.logInfoSpreadsheetApp.getActiveSpreadsheet().toast の両方で通知する。

const addedCount  = pipelineEvents.length;
const addedAmount = pipelineEvents.reduce(function(s, e){ return s + (e.inAmt || 0); }, 0);
SpreadsheetApp.getActiveSpreadsheet().toast(
  'パイプライン ' + addedCount + ' 件 / 加重後 ¥' + addedAmount.toLocaleString() + ' を84タブに合流',
  '84_cf_daily_plan 更新完了', 8
);
if (warnings.length) Utils.logWarn('S-06 合流警告: ' + warnings.join(' / '));

影響範囲

ファイル / シート変更内容
600_report/606_datamart_daily_cf.jsdmBuildPlanCashflow_ にパイプライン合流ロジック追加
200_data/202_repository.jsPipelineRepository 新規追加
000_infra/003_contracts.jsPipelineDTO 新規追加
000_infra/002_constants.jsPIPELINE_PROBABILITIESgetPipelineProbability 追加
100_config/101_sys_config.jsWRK_INVC ヘッダーに 親パイプラインID(PIP) 追加 / 03_sys_params 既定値追加
400_domain/406_rpa_pipeline.jsINV 起票時に 親パイプラインID(PIP) を書き込む
800_ops/809_migration_s06.js32_wrk_invoice 列追加マイグレーション(新規)
84_cf_daily_plan シートデータソース 追加、計画-PIP 由来行の追加

注意事項

  1. 実績専用モード(isActualOnly)ではパイプライン合流をスキップ — 過去月スナップショットに見込みが混入しない。
  2. processedPipIds の比較は文字列かつ trim 後 — スプレッドシート由来の前後空白や型ゆらぎに耐える。
  3. PIP → INV 起票時の ID 記録が未実装だと二重計上のリスク — MAS-080(早期採番)と 406_rpa_pipeline.js の更新をセットで必ず反映する。
  4. parseDateToYm / addMonths の戻り値は 'YYYY-MM' 文字列 — Date 変換を挟まず、そのまま + '-' + day で組み立てる。
  5. 休日調整は Utils.adjustToBusinessDay を再利用 — 独自の祝日判定を書かない。
  6. src の値を集計ロジック側で特別扱いしない計画-PIP も通常の 計画 行と同様に日次集計へ流す(「データソース」列は表示のみ)。
  7. CF計上 列の値は文字列 TRUE/FALSE — ユーザーが CF 反映を個別に除外したパイプラインはフィルタで弾く。

エッジケース

#条件期待挙動
1継続月数 が 0スポット売上・初期費用のみ計上。MRR ループは回さない
2継続月数 が負数エラーとしてスキップ、warnings にログ
3入金ラグ(月) が 0当月入金(計上月 = 入金月)
4入金ラグ(月) が負数月数を負方向に加算(例: -1 なら前月入金)。addMonths は負数対応
5スポット売上・初期費用継続月額(MRR) がいずれも 0生成イベント 0 件、スキップ
6片方が負数エラーとしてスキップ、warnings にログ
7計上開始年月 が空欄スキップ、マート更新ログに警告を出力
8計上開始年月 が不正フォーマット(parseDateToYm"" を返す)スキップ、警告ログ
9確度(ヨミ)Constants.PIPELINE_PROBABILITIES に存在しない確率 0(計算除外)として扱う。警告ログ
10確度(ヨミ) が閾値未満(例: CF_PIPELINE_MIN_PROBABILITY=0.8Bヨミ (確度50%)除外(ログ不要)
11有効フラグ = FALSE除外(CLAUDE.md の全処理スキップ規約に準拠)
12CF計上 = FALSE除外(ユーザー明示除外)
13同じ PIP_ID が 32_wrk_invoice.親パイプラインID(PIP) に存在除外(二重計上防止)
14入金日 が 29〜31 で対象月に存在しない日Utils.adjustToBusinessDay が実在日へ丸めるため、月末扱い
15休日調整 が空欄既定値 (前営業日調整)
16isActualOnly = true(過去月スナップショット表示)パイプライン合流を丸ごとスキップ
17CF_INCLUDE_PIPELINE = FALSEマスターフラグで合流スキップ
1821_bud_pipeline に 1 件も該当データがないpipelineEvents.length === 0。通知はサマリ 0 件として出す

実データ検証

  1. dev 環境で 21_bud_pipeline に下記テストレコードを 3 件投入:
    • a) 閾値超 Aヨミ (確度80%)・MRR 継続 6 ヶ月・ラグ 1 ヶ月・入金日 25
    • b) 閾値未満 Bヨミ (確度50%)(合流されないことを確認)
    • c) 既に 32_wrk_invoice.親パイプラインID(PIP) に登録済みの PIP_ID(二重計上防止が効くことを確認)
  2. dmBuildPlanCashflow_ を実行し、84_cf_daily_plan の データソース 列を目視確認。
  3. CF_PIPELINE_USE_WEIGHTING=FALSE に切替て再実行し、加重と非加重の金額差を比較。
  4. CF_INCLUDE_PIPELINE=FALSE に切替て再実行し、84 タブに 計画-PIP 行が一切出ないことを確認。
  5. MAS-008(Cash Runway)が改修前後で値を変えることを確認(見込み入金が加算されて延命)。

関連ドキュメント

人間が検討すべき事項(Human-in-the-Loop)

1. ユーザーによる挙動制御

03_sys_params シートに以下の設定項目を追加し、ユーザーが CF 予測の挙動を制御できるようにする。

キー既定値役割
CF_INCLUDE_PIPELINEBOOLEANTRUEパイプライン売上を CF に含めるかのマスターフラグ
CF_PIPELINE_MIN_PROBABILITYNUMBER0.8計算に含める最低確率(これ未満の確度は無視)
CF_PIPELINE_USE_WEIGHTINGBOOLEANTRUE金額に確率を乗じるか(加重)のフラグ。FALSE なら閾値超の案件を 100% で計上

運用想定:

  • 営業最終予算の策定フェーズでは CF_PIPELINE_MIN_PROBABILITY=0.5USE_WEIGHTING=TRUE で広めの見込みを加重反映。
  • 融資面談・投資家説明など「確実性重視」の場面では MIN_PROBABILITY=0.9USE_WEIGHTING=TRUE で保守的に。
  • 「Aヨミ以上は絶対取る」前提のストレッチ計画では MIN_PROBABILITY=0.8USE_WEIGHTING=FALSE で 100% 計上。

2. 結果の透明性

  1. 84_cf_daily_plan に「データソース」列を追加し、各行が 実績-INV / 計画-INV / 計画-PIP のどれかを明記する。
  2. マート更新完了時のトースト(または UI ダイアログ)で、以下を必ず表示する。
    • 追加されたパイプライン見込みの件数
    • 加重後の合計金額
    • スキップされた件数(閾値未満・確度未定義・不正値)
  3. warnings に積まれたレコード(確度未定義・日付不正など)は Utils.logWarn で必ず記録し、運用者が 01_sys_log で追跡できるようにする。

3. 確度加重の会計解釈

  • CF 予測に確率加重を適用するのは「資金繰り予測」のためであり、P/L 見込みや予算策定とは独立した概念である。
  • 見込み売上を実績 P/L に流し込むものではないため、92_fs_pl や 91_fs_bs への影響は無い(本案件のスコープ外)。
  • 税務申告・監査対応の P/L・B/S 数値には影響しないことを、仕様書・ユーザーガイドの両方で明記する。

実装プロンプト

以下のプロンプトを順に Claude Code に投入すれば、本仕様を段階的に実装できる。各ステップは独立コミット粒度を想定。


実装プロンプト 1/5: 定数・DTO・Repository の追加

000_infra/002_constants.js, 000_infra/003_contracts.js, 200_data/202_repository.js に以下を追加してください。既存のコメント・順序・スタイルに合わせ、動作を変えないこと。

1. 002_constants.js の Constants オブジェクトに以下を追加:
   - PIPELINE_PROBABILITIES: { "Sヨミ (確度95%)": 0.95, "Aヨミ (確度80%)": 0.80, "Bヨミ (確度50%)": 0.50, "Cヨミ (確度30%)": 0.30, "Dヨミ (確度10%)": 0.10, "失注": 0.0 }
   - getPipelineProbability(label): PIPELINE_PROBABILITIES[label] が存在すれば返す。存在しなければ null。空文字・undefined も null。

2. 003_contracts.js に @typedef PipelineDTO を定義(キー一覧は dev_s-06 Step 1-2 の表に従う)。既存の InvoiceDTO の書式に合わせる。

3. 202_repository.js に PipelineRepository を追加。InvoiceRepository と同一パターンで findAll/save/append を実装。シートキーは "BUD_PIPE"、物理シート名は "21_bud_pipeline"。

完了後、node --check で全ファイルの構文をチェックすること。

実装プロンプト 2/5: 32_wrk_invoice に 親パイプラインID(PIP) 列を追加

100_config/101_sys_config.js の setupAllSchemas 内、WRK_INVC のヘッダー配列に "親パイプラインID(PIP)" を追加してください。位置は "親発注ID(ORD)" の直後。

併せて 800_ops/809_migration_s06.js を新規作成し、既存 32_wrk_invoice に列が存在しない場合のみ列を挿入する冪等スクリプト migrationS06() を実装。実装ルール:
- CLAUDE.md の「マイグレーションスクリプト運用ガイドライン」に従う
- Utils.logInfo と SpreadsheetApp.getUi().alert の両方で完了ログ
- 101_sys_config.js の「🔧 マイグレーション」メニューに migrationS06 を登録

完了後 node --check で構文チェック。

実装プロンプト 3/5: 406_rpa_pipeline.js で PIP_ID を INV に書き込み

400_domain/406_rpa_pipeline.js を編集し、パイプライン→INV 起票処理で、生成する InvoiceDTO の 親パイプラインID(PIP) フィールドに起票元の PIP_ID を書き込むようにしてください。

- PIP_ID は S-08 で早期採番された 21_bud_pipeline.管理ID を利用
- 既存の冪等性チェック・ID 生成ロジックは変えない
- テスト: dev 環境で 1 件のパイプラインから INV を起票し、32_wrk_invoice の 親パイプラインID(PIP) 列に値が入ることを確認

完了後 node --check。

実装プロンプト 4/5: dmBuildPlanCashflow_ にパイプライン合流ロジック追加

600_report/606_datamart_daily_cf.js の dmBuildPlanCashflow_ を改修し、32_wrk_invoice 由来の cashEvents 構築ブロック直後に以下を追加してください。

実装内容(詳細は dev_s-06 Step 2):
1. Constants.getParam で CF_INCLUDE_PIPELINE / CF_PIPELINE_MIN_PROBABILITY / CF_PIPELINE_USE_WEIGHTING を取得
2. isActualOnly または CF_INCLUDE_PIPELINE=FALSE なら合流スキップ
3. invDtos から processedPipIds: Set を構築(親パイプラインID(PIP) 非空のもの)
4. PipelineRepository.findAll() でパイプラインを取得。有効フラグ=TRUE かつ CF計上≠FALSE かつ processedPipIds に含まれないもののみ対象
5. 各パイプラインに対し、スポット初月 + MRR 月数ぶん の入金イベントを生成。日付は Utils.parseDateToYm/addMonths/adjustToBusinessDay を使用
6. 確率加重は USE_WEIGHTING=TRUE なら金額 * prob、FALSE なら 1.0 倍
7. src は "計画-PIP"、memo は "[PIP:<id>] <案件名> (<kind>, 確度=<ヨミ>)"
8. 生成イベントを cashEvents に Array.prototype.push.apply で合流
9. 合流件数・加重後合計金額をトースト通知 + Utils.logInfo、warnings は Utils.logWarn

さらに 84_cf_daily_plan のヘッダー出力に "データソース" 列を追加し、各行の src を書き出す。

追加ユーティリティ関数 buildPipelineEvent_ はファイル内ローカルとして定義。

完了後 node --check。dev 環境で dmBuildPlanCashflow_ を実行し、84_cf_daily_plan に "計画-PIP" 行が出ること・既起票 PIP_ID が除外されることを確認。

実装プロンプト 5/5: 03_sys_params の既定値投入

100_config/101_sys_config.js の setupAllSchemas 内、03_sys_params 初期投入処理(または 809_migration_s06.js)で以下のキーを冪等に追加してください:

- CF_INCLUDE_PIPELINE (BOOLEAN, 既定 TRUE)
- CF_PIPELINE_MIN_PROBABILITY (NUMBER, 既定 0.8)
- CF_PIPELINE_USE_WEIGHTING (BOOLEAN, 既定 TRUE)

既存キーがあればスキップ(重複投入しない)。完了後、node --check と dev 環境で setupAllSchemas を再実行し、3 キーが入ることを確認。

推奨実行モデル

Stepモデル理由
実装プロンプト 1/5: 定数・DTO・RepositorySonnet既存パターンの踏襲が中心。判断要素は中程度
実装プロンプト 2/5: DDL 列追加・マイグレーションSonnet既存マイグレーションパターン適用。挿入位置の判断あり
実装プロンプト 3/5: 406_rpa_pipeline 書き込み対応Sonnet既存起票ロジックを読み、非破壊で修正点を特定する必要
実装プロンプト 4/5: dmBuildPlanCashflow_ 改修Opus会計ロジック(二重計上防止・確度加重)と複数ファイル横断の設計判断。最もリスクが高い
実装プロンプト 5/5: 03_sys_params 既定値投入Haikuコード完全定義済。判断要素ほぼ無し

変更履歴

日時変更内容
2026-04-19初版作成(MAS-078: 84タブにパイプライン売上を合流。二重計上防止・確度加重・マスターフラグ・データソース列追加)

仕様書作成プロンプト

本仕様書を生成する際に使用した instruction(クリックで展開)
<instruction>
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】
1. 拡張思考の使い分け: Phase 1で設計を確定させ、Phase 2では出力に徹する。
2. テキスト報告の禁止: 説明は1文以内。直ちに tool を呼ぶ。
3. 4-5 分割の Write/Edit 実行: 2-1(骨格)/2-2(前半)/2-3a(後半)/2-3b(プロンプト)/2-4(<details>記録)に分割。
4. 各 Step で何を書くかを具体指示: 出力時に設計判断を再考しない。

======================================================================
あなたはGAS会計システムのシニア開発者兼仕様書ライターです。
CLIエージェント「Claude Code」として、案件 S-06「84タブにパイプライン売上を合流」の開発仕様書を作成してください。

## Phase 1: 実行前タスク(テキスト報告禁止。即座にツール実行)
1. `docs/_internal/TODO_future.md` でS-06の要件(概要、期待効果、人間が検討すべき事項)を深く把握。
2. 以下の関連するGASコードやマスタをツールで調査し、設計のインプットとする。
    - `21_bud_pipeline`シート (MCP): 追加するデータソースの列構造・実データを確認。
    - `32_wrk_invoice`シート (MCP): 既存データソース。特に`親パイプラインID(PIP)`列の有無を確認。
    - `84_cf_daily`シート (MCP): 出力先のシート。
    - `608_datamart_daily_cf.js`: (ファイルが存在する場合) 84タブを生成する既存ロジック。修正対象の最有力候補。
    - `202_repository.js`: `PipelineRepository`の有無を確認。なければ`InvoiceRepository`等を参考に作成する必要がある。
    - `004_utils.js`: `addMonths`, `parseDateToYm`, `adjustToBusinessDay`等の再利用可能な日付関数。
    - `003_contracts.js`: `PipelineDTO`の有無を確認。なければ定義する必要がある。
    - `002_constants.js`: 確度マッピング等、追加すべき定数がないか確認。

## Phase 2: 仕様書の分割作成
出力先: `docs/dev/dev_s-06_pipeline_merge_to_cf.md`
**【重要】絶対に1回のツール呼び出しで全内容を出力せず、以下のStepに分割して実行すること。**

### Step 2-1: 骨格の作成 (File Write)
- `dev_spec_prompt_template.md`に準拠したセクション見出しのみで構成された、空の仕様書ファイルを作成する。

### Step 2-2: 前半セクションの追記 (File Edit または Bash)
※アーキテクトからの指示:
- **【アーキテクチャ方針】**
    - `608_datamart_daily_cf.js`(または同等の日次CFマートビルダー)を修正する方針とする。
    - 既存の`32_wrk_invoice`由来のデータに加え、`21_bud_pipeline`シートのデータを読み込むロジックを追加する。
    - データ読み込みはリポジトリパターンを適用する。`202_repository.js`に`PipelineRepository`がなければ、`InvoiceRepository`を参考に新規作成すること。
    - パイプラインデータから入金予定レコード(日付、金額、摘要等)をメモリ上で生成し、`32_wrk_invoice`由来のレコードと結合してから日次で集計する。
- **【使用すべき既存関数】**
    - 日付計算には`Utils.addMonths`, `Utils.parseDateToYm`, `Utils.adjustToBusinessDay`を全面的に再利用すること。
    - データ変換には`Contracts.toDtoList`, `Contracts.toDto`を利用すること。
- **【二重計上防止策】**
    - パイプライン案件が受注され`32_wrk_invoice`に登録された際の二重計上を、IDベースで厳密に防止する。
    - **前提**: `32_wrk_invoice`に`親パイプラインID(PIP)`列が存在すること。この列はS-08で早期採番されたPIP_IDを記録するために使用する。もし存在しない場合、本案件のスコープとしてDDL追加を仕様に含める。
    - **実装**:
        1. マート生成ロジックの冒頭で、`32_wrk_invoice`を読み込み、`親パイプラインID(PIP)`が設定されているレコードからPIP_IDの一意なセット(例: `processedPipIds = new Set()`)を作成する。
        2. `21_bud_pipeline`のデータを読み込んだ後、各レコードの`予算ID` (PIP_ID)が`processedPipIds`に含まれている場合は、そのパイプライン案件を計算対象から除外する。
- **【定数とDTO】**
    - `002_constants.js`に、確度文字列と確率数値をマッピングする`PIPELINE_PROBABILITIES`オブジェクトを追加する。例: `{'Aヨミ (確度80%)': 0.8, 'Bヨミ (確度50%)': 0.5}`。
    - `003_contracts.js`に、`21_bud_pipeline`シートに対応する`PipelineDTO`の型定義を追加する。

### Step 2-3a: エッジケース〜人間検討事項の追記 (File Edit または Bash)
※アーキテクトからの指示:
- **【エッジケーステーブル】**
    - `継続月数`が0または負数の場合: 0の場合はスポット売上のみ、負数の場合はエラーとしてスキップ。
    - `入金ラグ(月)`が0または負数の場合: 仕様を明確化(例: 0は当月、-1は前月)。
    - `スポット売上・初期費用`または`継続月額(MRR)`が0または負数の場合: 0はスキップ、負数はエラーとしてスキップ。
    - `計上開始年月`が空欄または不正フォーマットの場合: スキップし、マート更新ログに警告を出力。
    - `確度(ヨミ)`の文字列が`Constants.PIPELINE_PROBABILITIES`に存在しない場合: 確率0として扱い、計算に含めない。ログに警告を出力。
- **【人間が検討すべき事項 (Human-in-the-Loop)】**
    - **ユーザーによる挙動制御**:
        - `03_sys_params`シートに以下の設定項目を追加し、ユーザーがCF予測の挙動を制御できるようにする。
            - `CF_INCLUDE_PIPELINE` (BOOLEAN): パイプライン売上をCFに含めるかのマスターフラグ (デフォルト: `TRUE`)。
            - `CF_PIPELINE_MIN_PROBABILITY` (NUMBER): 計算に含める最低確率 (デフォルト: `0.8`)。これ未満の確度の案件は無視される。
            - `CF_PIPELINE_USE_WEIGHTING` (BOOLEAN): 金額に確率を乗じるか(確度加重)のフラグ (デフォルト: `TRUE`)。`FALSE`の場合は最低確率を超えた案件は金額を100%で計上。
    - **結果の透明性**:
        - `84_cf_daily`シートに「データソース」列を追加し、各行が`実績-INV`または`計画-PIP`のどちらに由来するかを明記する。
        - マート更新完了時のトースト通知またはダイアログに、追加されたパイプライン見込みの件数と合計金額(加重後)のサマリーを表示する。

### Step 2-3b: 実装プロンプト〜変更履歴の追記 (File Edit または Bash)
- Step 2-2, 2-3aの指示に基づき、Claude Codeが実装作業を行えるレベルまで具体的な実装プロンプトを作成する。

### Step 2-4: 仕様書作成プロンプトの記録 (File Edit または Bash)
- 仕様書の末尾に`<details>`タグを設け、この`<instruction>`の全文を、変更せずにそのまま記録すること。

## Phase 3: `_config.json` への追記と構文チェック
- 仕様書作成後、`docs/_config.json`の`nav`配列 §E.6セクションに追記する。
- 全体の構文が正しいか確認する。
</instruction>