1. 概要

焦点質問: INVと発注(ORD)はどのように自動紐づけされるか?

RPA起票時に 31_wrk_order (ORD) を自動作成し、32_wrk_invoice (INV) の 親発注ID(ORD) に紐づける。 Action A 実行時に ORD の発注残高が自動減算され、契約消化率を追跡できるようにする。

1.1 背景・課題

INV(請求)が単体で存在する状態では、契約単位の消化状況を把握できない。ORDを自動作成しINVと紐づけることで、発注残高の追跡と予実管理を実現する。

1.2 対象ソース(段階的に実装)

#ソースORD粒度ステータス
122_bud_headcount (HC)従業員1人×開始〜終了年月Phase 1 (今回)
223_bud_subscription (SaaS)サブスク1契約Phase 2
324_bud_capex_loan (CAPEX)借入1件Phase 3
421_bud_pipeline (Pipeline)案件1件Phase 4
525_bud_adhoc (Adhoc)申請1件Phase 5

2. 設計判断

#選択肢メリットデメリット選定
D1ORD粒度を「従業員×開始〜終了年月」とする契約期間ごとの消化率を正確に追跡可能年度またぎで別ORDが必要採用
D2ORD粒度を「従業員単位」(期間不問)ORD数が少ない年度の区切りが曖昧になる不採用
D3ORD検索キーを 参照元ID + 開始年月 とする冪等性が保証される(同一キーで重複作成防止)複合キーのため検索コストがやや高い採用
D4列参照をヘッダー名ベース (indexOf) に統一列追加・並び替えに強い。コーディング規約準拠indexOf呼び出しのオーバーヘッド(軽微)採用
D5全予算タブのID列名を「管理ID」に統一プレフィクスで種別判別可能。コード簡素化既存データのマイグレーション必要採用

3. 変更内容

3.1 スキーマ変更

3.1.1 31_wrk_order のリニューアル(15列→19列)

旧ヘッダー(15列)

["有効フラグ","発注ID(ORD)","起票日時","起票者","発注ステータス",
 "取引先名","PJ名","契約・件名","契約形態",
 "税抜金額_発注","消費税額_発注","税込金額_発注","発注残高(自動計算)",
 "摘要","証憑URL"]

新ヘッダー(19列)

["有効フラグ","発注ID(ORD)","起票日時","起票者",
 "取引先名","契約・件名","摘要","契約形態",
 "開始年月","終了年月",
 "税抜金額_発注","消費税額_発注","税込金額_発注","発注残高(自動計算)",
 "PJ名","発注ステータス","参照元区分","参照元ID",
 "証憑URL"]

列マップ

#カラム名グループ備考
1A有効フラグ管理checkbox
2B発注ID(ORD)管理ORD_YYYYMMDD_NNNN
3C起票日時記録yyyy-mm-dd hh:mm
4D起票者記録
5E取引先名誰にpulldown
6F契約・件名何を自由入力
7G摘要何を契約の補足情報
8H契約形態何をpulldown
9I開始年月いつ新規 yyyy-mm
10J終了年月いつ新規 yyyy-mm (空=無期限)
11K税抜金額_発注いくら#,##0
12L消費税額_発注いくら#,##0
13M税込金額_発注いくら#,##0
14N発注残高(自動計算)いくら#,##0 (Action Aで自動減算)
15OPJ補助pulldown
16P発注ステータス補助pulldown
17Q参照元区分補助新規 (HC/SaaS/CAPEX/Pipeline/Adhoc)
18R参照元ID補助新規 (EMP_0001等)
19S証憑URL記録

参照元区分の値

ソースタブ参照元IDの例
HC22_bud_headcountEMP_0001
SaaS23_bud_subscriptionSUB_0001
CAPEX24_bud_capex_loanCPX_0001
Pipeline21_bud_pipelinePIP_0001
Adhoc25_bud_adhocADH_0001

ソース別の開始年月・終了年月

ソース開始年月終了年月
HC22の開始年月22の終了年月 (空なら適用年度末 {年度+1}-03)
SaaS23の開始・契約年月23の次回更新・終了年月
CAPEX24の会社支払開始年月開始 + 返済月数 − 1
Pipeline21の計上開始年月開始 + 継続月数 − 1
Adhoc25の発生日(P/L計上日)同月 (単発)

3.1.2 ソースタブの管理ID列名を統一

全予算タブのID列名を 「管理ID」 に統一する。プレフィクス (EMP_/SUB_/CPX_/PIP_/ADH_) で種別が判別できるため、列名を分ける必要がない。

タブ旧列名新列名変更
22_bud_headcount管理ID管理IDなし
23_bud_subscription契約ID管理ID要変更
24_bud_capex_loan管理ID管理IDなし
21_bud_pipeline案件ID管理ID要変更
25_bud_adhoc(未確認)管理ID要確認

3.2 ロジック変更

3.2.1 Phase 1: HC → ORD自動紐づけ

ORD 1件の定義

項目
粒度従業員1人 × 開始年月〜終了年月
ORD_IDORD_{yyyyMMdd}_{NNNN} (自動発番)
起票者RPA自動起票
発注ステータス発注済
取引先名HC の取引先名 (空なら氏名)
PJ名指定なし_共通費など
契約・件名{氏名} {雇用形態} {適用年度}年度
契約形態HC の雇用形態
開始年月HC の開始年月
終了年月HC の終了年月 (空なら適用年度末 {適用年度+1}-03)
参照元区分HC
参照元IDHC の管理ID (例: EMP_0001)
税抜金額_発注(月額給与 − 源泉消費税) × 契約月数
消費税額_発注源泉消費税額_発注 × 契約月数
税込金額_発注月額給与 × 契約月数
発注残高税込金額_発注 と同額 (初期値)
摘要【RPA:HC】{適用年度}年度 {氏名} 年間契約

契約月数の算出: 開始年月〜終了年月の月数(終了月を含む)。 例: 2025-11 〜 2026-03 → (2026-2025)×12 + (3-11) + 1 = 5ヶ月 終了年月が未設定の場合は {適用年度+1}-03 をフォールバック適用後に計算。

ORD検索・作成ロジック(マトリクス)

STEP処理入力(物理名: タブ.列)処理詳細 / 変換ロジック出力(物理名: タブ.列)例外処理
O1.1ORDマップ構築31_wrk_order.S,I列 (参照元ID, 開始年月)有効行を参照元ID + "|" + parseDateToYm(開始年月)でMap化変数: ordMap { key: ordId }
O1.2ORDキー生成22_bud_headcount.B,J列 (管理ID, 開始年月)ordKey = 管理ID + "|" + 開始年月変数: ordKey
O1.3ORD検索変数: ordMapordMap内に存在 → 既存ordIdを使用変数: ordId
O1.4ORD新規作成ordKey不存在時generateOrdId_() で発番、buildOrdRow_() で行構築。参照元区分="HC", 参照元ID=管理ID31_wrk_order (新規行)
O1.5INV紐づけ変数: ordId全INV Row (1,1b,2b,2,3,4,5) に 親発注ID(ORD) = ordId を設定32_wrk_invoice.C列
O1.6一括書き込み変数: newOrdRowswriteOrdRows_() で31タブ末尾に追記。バリデーション一時解除→書込→再適用31_wrk_order

ヘルパー関数

関数名パターン備考
generateOrdId_(ordSheet, dateStr, offset)generateInvId_ と同一ORD_{dateStr}_{NNNN} 形式。キャッシュで連番管理
buildOrdRow_(ordHeaders, fields)buildInvRow_ と同一ヘッダー名ベースで値をセット
writeOrdRows_(ordSheet, ordHeaders, rows)writeInvRows_ と同一一括setValues + バリデーション一時解除→再適用
buildOrdMap_(ordData)既存ORDマップ構築 { "参照元ID|開始年月": "ORD_xxx" }

3.2.2 冪等性(二重起票防止)

チェック対象方法
ORD の重複作成防止参照元ID + 開始年月 で既存検索
INV の重複既存の摘要ベース重複チェック (変更なし)

3.2.3 101_sys_config.js の変更

WRK_ORDR headers 更新

'WRK_ORDR': { headers: ["有効フラグ","発注ID(ORD)","起票日時","起票者",
  "取引先名","契約・件名","摘要","契約形態",
  "開始年月","終了年月",
  "税抜金額_発注","消費税額_発注","税込金額_発注","発注残高(自動計算)",
  "PJ名","発注ステータス","参照元区分","参照元ID",
  "証憑URL"], color: "#b45f06" },

WRK_ORDR フォーマット処理の更新

if (key === 'WRK_ORDR') {
  // C(3):起票日時 I(9):開始年月 J(10):終了年月
  // K(11):税抜金額_発注 L(12):消費税額_発注 M(13):税込金額_発注 N(14):発注残高
  sheet.getRange("C2:C").setNumberFormat('yyyy-mm-dd hh:mm');
  sheet.getRange("I2:J").setNumberFormat('yyyy-mm');
  sheet.getRange("K2:N").setNumberFormat('#,##0');
  if (maxR > 1) sheet.getRange(2, 1, maxR - 1, 1).insertCheckboxes();
}

setVali の列番号更新

setVali('WRK_ORDR', 5, 'E', '31_wrk_order');   // 取引先名 (E列)
setVali('WRK_ORDR', 15, 'H', '31_wrk_order');  // PJ名 (O列)
setVali('WRK_ORDR', 16, 'S', '31_wrk_order');  // 発注ステータス (P列)

BUD_SUBS, BUD_PIPE の headers 更新

// 23_bud_subscription: "契約ID" → "管理ID"
// 21_bud_pipeline: "案件ID" → "管理ID"

3.2.4 403_subledger_engine.js の変更

Action A の ORD残高減算をヘッダー名ベース (indexOf) に変更:

// 旧 (列番号ハードコード)
const currentBal = Number(ordData[i][12]);
const totalIncTax = Number(ordData[i][11]) || 0;
ordSheet.getRange(ordMap[ordId].rowIndex, 13).setValue(newBal);

// 新 (ヘッダー名ベース)
const ordH = ordData[0];
const iOrdId = ordH.indexOf('発注ID(ORD)');
const iOrdTotalIncTax = ordH.indexOf('税込金額_発注');
const iOrdBalance = ordH.indexOf('発注残高(自動計算)');
// ... indexOf で取得した値を使用

4. 影響範囲

影響対象影響内容対応
101_sys_config.jsWRK_ORDR headers リニューアル(19 列)§3.2.3
101_sys_config.jsBUD_SUBS / BUD_PIPE のキー列名を「管理 ID」に統一§3.2.3
401_bat_rpa.jsORD ヘルパー 4 関数追加§3.2.1
401_bat_rpa.jsgenerateHcInvoices に ORD 検索/作成 + 親発注 ID 設定§3.2.1
403_subledger_engine.jsORD 列参照をヘッダー名ベース化§3.2.4

§3.2.1 詳細関数: generateOrdId_ / buildOrdRow_ / writeOrdRows_ / buildOrdMap_


5. テスト仕様

テストIDテスト名前提条件期待結果
T1DDL実行setupAllSchemas実行31_wrk_order に新列(I〜J:年月, Q:参照元区分, R:参照元ID)が追加される
T2HC起票 (ORD未存在)22_bud_headcountに有効行あり、31_wrk_orderにORDなし31_wrk_order に ORD 1行作成、INV全行に親発注ID設定
T3同月再実行 (冪等性)T2実行済みORD追加なし、INV追加なし
T4翌月実行 (ORD既存)T2実行済み、翌月に再実行既存ORD_IDを再利用 (参照元ID+開始年月で検索)、INVのみ追加
T5Action A 実行ORD・INVが存在する状態でAction AORD発注残高 (N列) が INV請求総額分だけ減算される
T62人分同時起票22_bud_headcountに有効行2行ORD 2行 + INV 各人分が正しく紐づく
T7年度またぎ同一従業員で開始年月が異なる2行開始年月が異なれば別ORDが作成される

付録A: 将来拡張(Phase 2以降)

PhaseソースORD粒度参照元区分参照元ID開始年月終了年月
2SaaS契約1件SaaSSUB_NNNN開始・契約年月次回更新・終了年月
3CAPEX借入1件CAPEXCPX_NNNN会社支払開始年月開始 + 返済月数 − 1
4Pipeline案件1件PipelinePIP_NNNN計上開始年月開始 + 継続月数 − 1
5Adhoc申請1件AdhocADH_NNNN発生日(P/L計上日)同月