1. 基本情報

焦点質問: 21タブのパイプライン案件をどうマートに取り込むか?

項目内容
ファイル601_datamart_ingest.js
主要関数dmIngestPipelinePlanData_(ctx, sheetPipe)
役割21_bud_pipeline から確度加重・期間展開した仮想イベントを生成し、計画データマートへ供給
呼び出し元602_datamart_main.jsbuildBudgetTrendDataMart

アーキテクチャ図(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管理IDString入力案件の一意識別子
3PJ・案件名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加重
A0.80加重
B0.50加重
C0.25加重
D0.10加重
N% (数値%)N/100加重
100% / 0%スキップ (prob >= 1.0 or prob <= 0)

出力: planData (1イベント = 1オブジェクト)

フィールド説明
pYmStringP/L計上年月'2026-04'
sYmString入金予定年月 (pYm + 入金ラグ)'2026-05'
accString売上科目'売上高'
amtNumber確度加重後の税抜金額 (Math.round)40000
bookedBoolean常に false (計画データ)false
isBsForcenull常に nullnull
noCashBoolean常に falsefalse

出力: viewData (1イベント = 1配列、明細ダンプ用)

#内容
0管理ID'PL-001'
1計上年月'2026-04'
2入金予定年月'2026-05'
3PJ・案件名'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.targetMonthslastMonth配列末尾

4.2 行ループ: フィルタリング

STEP処理入力出力条件
4有効フラグチェック有効フラグ列continueFALSE → スキップ
5確度変換確度(ヨミ)prob (数値)上記変換テーブルに従う
6確度スキップ判定probcontinueprob <= 0 or prob >= 1.0 → スキップ
7計上開始年月パース計上開始年月startYmパース失敗 → スキップ
8各フィールド取得各列pjName, typeStr, acc, lag, mgrId, vendor, payMethod, orgNameacc 空→'売上高', lag 空→0

4.3 スポット売上生成

STEP処理入力出力条件
9スポット金額取得スポット売上・初期費用spot
10確度加重spot × probweightedSpotMath.round で丸め
11入金予定年月算出startYm + lagsYmSpot
12planData/viewData に追加上記全てevents[], viewRows[]spot > 0 かつ startYm <= lastMonth

4.4 MRR ループ展開

STEP処理入力出力条件
13MRR金額取得継続月額(MRR)mrr
14確度加重mrr × probweightedMrrMath.round で丸め
15継続月数決定継続月数, 契約形態dur0/空→継続なら120, それ以外は1
16月次ループ (m=0..dur-1)startYm + mcurYmcurYm > lastMonth → BREAK
17入金予定年月算出curYm + lagsYmMrr毎月ごとに算出
18planData/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-04100,000001
テスト案件B継続売上高A(80%)2026-04050,00031

期待結果

テストIDテスト名前提条件期待結果
PI-01スポット売上の確度加重テスト案件A: B(50%), スポット 100,000planData 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-03MRR ループ展開テスト案件B: A(80%), MRR 50,000, 3ヶ月planData 3件: pYm=2026-04/05/06, 各 amt=40,000 (50,000×0.8)
PI-04MRR 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有効フラグ=FALSEplanData/viewData ともに0件
PI-08計上開始年月が空計上開始年月=空planData/viewData ともに0件
PI-09lastMonth 超過打ち切りMRR 120ヶ月, lastMonth=2026-06curYm > 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 に出力