1. 基本情報
焦点質問: 21タブのパイプライン案件をどうマートに取り込むか?
| 項目 | 内容 |
|---|
| ファイル | 601_datamart_ingest.js |
| 主要関数 | dmIngestPipelinePlanData_(ctx, sheetPipe) |
| 役割 | 21_bud_pipeline から確度加重・期間展開した仮想イベントを生成し、計画データマートへ供給 |
| 呼び出し元 | 602_datamart_main.js の buildBudgetTrendDataMart |
アーキテクチャ図(Mermaid)
flowchart LR
A[21_bud_pipeline] -->|有効行読込| B[dmIngestPipelinePlanData_]
B -->|確度加重 & 期間展開| C{戻り値}
C -->|planData| D[buildBudgetTrendDataMart の planData に合流]
C -->|viewData| E[51_list_pipeline_plan に出力]
2. インターフェース定義
| 関数 | 引数 | 戻り値 | トリガー |
|---|
dmIngestPipelinePlanData_ | ctx (データマートコンテキスト), sheetPipe (21タブのシートオブジェクト) | { planData: Array, viewData: Array } | buildBudgetTrendDataMart から呼び出し |
早期リターン条件:
sheetPipe が null/undefined → 空の { planData: [], viewData: [] } を返却
- シートにヘッダー行のみ (データ0行) → 同上
3. データスキーマ
入力: 21_bud_pipeline 使用カラム
| # | 列名 | 型 | 入力/自動 | 説明 | 制約 |
|---|
| 1 | 有効フラグ | Boolean | 入力 | FALSE → 行スキップ | — |
| 2 | 管理ID | String | 入力 | 案件の一意識別子 | — |
| 3 | PJ・案件名 | String | 入力 | viewData の案件名表示用 | — |
| 4 | 取引先名 | String | 入力 | viewData の取引先表示用 | — |
| 5 | 組織名 | String | 入力 | viewData の組織名表示用 | — |
| 6 | 契約形態 | String | 入力 | 継続/スポット判定 + viewData | — |
| 7 | 売上科目 | String | 入力 | P/L科目名 | 空の場合「売上高」 |
| 8 | 確度(ヨミ) | String | 入力 | 確度ランクまたはN% | 下表参照 |
| 9 | 計上開始年月 | Date/String | 入力 | P/L計上月の起点 | 必須(空→スキップ) |
| 10 | スポット売上・初期費用 | Number | 入力 | 1回きりの売上金額(税抜) | — |
| 11 | 継続月額(MRR) | Number | 入力 | 月額売上金額(税抜) | — |
| 12 | 継続月数 | Number | 入力 | MRR展開の月数 | 0/空→契約形態で判定 |
| 13 | 入金ラグ(月) | Number | 入力 | 計上月→入金月のオフセット | 空→0 |
| 14 | 決済手段 | String | 入力 | viewData の決済手段表示用 | — |
確度(ヨミ) 変換テーブル
| ヨミ値 | 確度(数値) | 処理 |
|---|
| 失注 / 保留 | — | スキップ |
| 受注 / S | — | スキップ (確定案件→32タブINVで管理) |
| 内示 | 0.90 | 加重 |
| A | 0.80 | 加重 |
| B | 0.50 | 加重 |
| C | 0.25 | 加重 |
| D | 0.10 | 加重 |
| N% (数値%) | N/100 | 加重 |
| 100% / 0% | — | スキップ (prob >= 1.0 or prob <= 0) |
出力: planData (1イベント = 1オブジェクト)
| フィールド | 型 | 説明 | 例 |
|---|
| pYm | String | P/L計上年月 | '2026-04' |
| sYm | String | 入金予定年月 (pYm + 入金ラグ) | '2026-05' |
| acc | String | 売上科目 | '売上高' |
| amt | Number | 確度加重後の税抜金額 (Math.round) | 40000 |
| booked | Boolean | 常に false (計画データ) | false |
| isBsForce | null | 常に null | null |
| noCash | Boolean | 常に false | false |
出力: viewData (1イベント = 1配列、明細ダンプ用)
| # | 内容 | 例 |
|---|
| 0 | 管理ID | 'PL-001' |
| 1 | 計上年月 | '2026-04' |
| 2 | 入金予定年月 | '2026-05' |
| 3 | PJ・案件名 | 'XX社 DXコンサル' |
| 4 | 取引先名 | 'XX株式会社' |
| 5 | 契約形態 | '継続' |
| 6 | 売上科目 | '売上高' |
| 7 | 確度 (数値) | 0.8 |
| 8 | 元の税抜金額 | 80000 |
| 9 | 確度加重後の税抜金額 | 40000 |
| 10 | 入金ラグ(月) | 1 |
| 11 | 決済手段 | '銀行振込' |
| 12 | 組織名 | '営業部' |
| 13 | 摘要 | 'MRR 3/12ヶ月目' or 'スポット' |
4. 処理ロジック
4.1 初期化・ヘッダー解析
| STEP | 処理 | 入力 | 出力 | 条件 |
|---|
| 1 | 早期リターン判定 | sheetPipe | 空の戻り値 | シートが null またはデータ0行 |
| 2 | ヘッダー行から各列インデックスを取得 | pData[0] | idx* 変数群 | indexOf でヘッダー名ベース |
| 3 | 対象期間の最終月を取得 | ctx.targetMonths | lastMonth | 配列末尾 |
4.2 行ループ: フィルタリング
| STEP | 処理 | 入力 | 出力 | 条件 |
|---|
| 4 | 有効フラグチェック | 有効フラグ列 | continue | FALSE → スキップ |
| 5 | 確度変換 | 確度(ヨミ) | prob (数値) | 上記変換テーブルに従う |
| 6 | 確度スキップ判定 | prob | continue | prob <= 0 or prob >= 1.0 → スキップ |
| 7 | 計上開始年月パース | 計上開始年月 | startYm | パース失敗 → スキップ |
| 8 | 各フィールド取得 | 各列 | pjName, typeStr, acc, lag, mgrId, vendor, payMethod, orgName | acc 空→'売上高', lag 空→0 |
4.3 スポット売上生成
| STEP | 処理 | 入力 | 出力 | 条件 |
|---|
| 9 | スポット金額取得 | スポット売上・初期費用 | spot | — |
| 10 | 確度加重 | spot × prob | weightedSpot | Math.round で丸め |
| 11 | 入金予定年月算出 | startYm + lag | sYmSpot | — |
| 12 | planData/viewData に追加 | 上記全て | events[], viewRows[] | spot > 0 かつ startYm <= lastMonth |
4.4 MRR ループ展開
| STEP | 処理 | 入力 | 出力 | 条件 |
|---|
| 13 | MRR金額取得 | 継続月額(MRR) | mrr | — |
| 14 | 確度加重 | mrr × prob | weightedMrr | Math.round で丸め |
| 15 | 継続月数決定 | 継続月数, 契約形態 | dur | 0/空→継続なら120, それ以外は1 |
| 16 | 月次ループ (m=0..dur-1) | startYm + m | curYm | curYm > lastMonth → BREAK |
| 17 | 入金予定年月算出 | curYm + lag | sYmMrr | 毎月ごとに算出 |
| 18 | planData/viewData に追加 | 上記全て | events[], viewRows[] | mrr > 0 |
5. 財務ロジック (FRD)
※ 本セクションは経理担当・CFOが検証可能な表現で記述。技術用語は使用しない。
→ 技術詳細: §4 参照
5.1 確度加重による計画売上の算出
パイプライン案件は受注確度に応じて金額を按分し、計画上の売上として計上する。
- 計画売上金額 = 税抜金額 × 確度(%)
- 端数は四捨五入(円未満切り捨て)
- 受注済み案件 (受注/S/100%) は請求データ (32タブ) で管理するため、パイプラインからは除外する
- 失注・保留案件は計画に含めない
5.2 計画B/Sにおける期ずれルール
計画データ(32タブ全INV + パイプライン)の期ずれ処理は以下のルールに従う。
| 区分 | 入金予定月の決定 | 期ずれ | B/S上の表示 |
|---|
| 経費(支出) | 発生月と同月 | なし | 未払金なし |
| 売上(収入) | 発生月 + 入金ラグ (回収期限) | あり | 売掛金が表示 |
| 資産計上 | 支払期限 | あり | 計上→支払期限で解消 |
設計意図:
- 経費: 発生月ベースで負債の全体像を把握する(実際の支払時期は日次資金繰り表で確認)
- 売上: 入金タイミングが資金繰りに直結するため、売掛金として計画B/Sに表示
- パイプライン売上: 確度加重金額 × 入金ラグで売掛金を表示し、将来の入金見通しを把握
5.3 データソース別の入金予定月
| ソース | 経費 (P/L費用) | 収入 (P/L売上) | B/S直接計上 |
|---|
| 請求データ (32タブ) | 発生月 | 決済日_計画 | 決済日_計画 |
| パイプライン (21タブ) | — | 発生月 + 入金ラグ(月) | — |
5.4 スポット売上と継続売上 (MRR) の展開
- スポット売上: 計上開始月に1回のみ計上
- 継続売上 (MRR): 計上開始月から継続月数分、毎月同額を計上
- 継続月数が未指定の場合: 契約形態「継続」は10年 (120ヶ月)、それ以外は1ヶ月
- 各月の入金予定月 = その月の計上月 + 入金ラグ
6. 冪等性・整合性保証
| 保証項目 | メカニズム | 検証方法 |
|---|
| 二重生成防止 | 毎回 events/viewRows を空配列から再生成(差分更新ではない) | 同一データで複数回実行し、結果が同一であることを確認 |
| 受注案件の二重計上防止 | 確度 >= 1.0 (受注/S/100%) はスキップ → 32タブINVとの重複を排除 | 受注ヨミの行が planData に含まれないことを確認 |
| 期間境界の整合性 | curYm > lastMonth で BREAK → ctx.targetMonths の範囲外イベントを生成しない | lastMonth 境界の月でイベントが正しく打ち切られることを確認 |
| 金額の一貫性 | Math.round(金額 × 確度) で各イベント個別に丸め | planData.amt と viewData[9] が一致することを確認 |
7. テスト仕様
テストデータ(21タブ)
| PJ・案件名 | 契約形態 | 売上科目 | 確度 | 計上開始年月 | スポット | MRR | 継続月数 | 入金ラグ |
|---|
| テスト案件A | スポット | 売上高 | B(50%) | 2026-04 | 100,000 | 0 | 0 | 1 |
| テスト案件B | 継続 | 売上高 | A(80%) | 2026-04 | 0 | 50,000 | 3 | 1 |
期待結果
| テストID | テスト名 | 前提条件 | 期待結果 |
|---|
| PI-01 | スポット売上の確度加重 | テスト案件A: B(50%), スポット 100,000 | planData 1件: pYm='2026-04', sYm='2026-05', amt=50,000 (100,000×0.5) |
| PI-02 | スポット viewData 生成 | 同上 | viewData 1件: 摘要='スポット', 確度=0.5, 元金額=100,000, 加重金額=50,000 |
| PI-03 | MRR ループ展開 | テスト案件B: A(80%), MRR 50,000, 3ヶ月 | planData 3件: pYm=2026-04/05/06, 各 amt=40,000 (50,000×0.8) |
| PI-04 | MRR viewData 摘要 | 同上 | viewData 3件: 摘要='MRR 1/3ヶ月目', 'MRR 2/3ヶ月目', 'MRR 3/3ヶ月目' |
| PI-05 | 失注スキップ | 確度(ヨミ)='失注' | planData/viewData ともに0件 |
| PI-06 | 受注スキップ | 確度(ヨミ)='受注' | planData/viewData ともに0件 (32タブINVで管理) |
| PI-07 | 有効フラグFALSE | 有効フラグ=FALSE | planData/viewData ともに0件 |
| PI-08 | 計上開始年月が空 | 計上開始年月=空 | planData/viewData ともに0件 |
| PI-09 | lastMonth 超過打ち切り | MRR 120ヶ月, lastMonth=2026-06 | curYm > lastMonth で BREAK、targetMonths 範囲内のみ生成 |
| PI-10 | シート未存在 | sheetPipe=null | 空の { planData: [], viewData: [] } を返却 |
付録A: 変更差分
viewData 追加時の既存コードとの差分。
| 箇所 | 変更前 | 変更後 |
|---|
| 戻り値 | return events (配列) | return { planData: events, viewData: viewRows } |
| ヘッダー読み込み | PJ・案件名を読んでいない | idxName を追加 |
| スポット売上ブロック | events.push のみ | events.push + viewRows.push |
| MRRブロック | events.push のみ | events.push + viewRows.push |
付録B: 呼び出し側への影響
602_datamart_main.js での呼び出しを変更:
// 変更前
var pipeEvents = dmIngestPipelinePlanData_(ctx, sheetPipe);
planData = planData.concat(pipeEvents);
// 変更後
var pipeResult = dmIngestPipelinePlanData_(ctx, sheetPipe);
planData = planData.concat(pipeResult.planData);
// pipeResult.viewData は 51_list_pipeline_plan に出力