最終更新: 2026/06/22 18:56
ORD 自動紐づけ — 31_wrk_order
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粒度 | ステータス |
|---|---|---|---|
| 1 | 22_bud_headcount (HC) | 従業員1人×開始〜終了年月 | Phase 1 (今回) |
| 2 | 23_bud_subscription (SaaS) | サブスク1契約 | Phase 2 |
| 3 | 24_bud_capex_loan (CAPEX) | 借入1件 | Phase 3 |
| 4 | 21_bud_pipeline (Pipeline) | 案件1件 | Phase 4 |
| 5 | 25_bud_adhoc (Adhoc) | 申請1件 | Phase 5 |
2. 設計判断
| # | 選択肢 | メリット | デメリット | 選定 |
|---|---|---|---|---|
| D1 | ORD粒度を「従業員×開始〜終了年月」とする | 契約期間ごとの消化率を正確に追跡可能 | 年度またぎで別ORDが必要 | 採用 |
| D2 | ORD粒度を「従業員単位」(期間不問) | ORD数が少ない | 年度の区切りが曖昧になる | 不採用 |
| D3 | ORD検索キーを 参照元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"]
列マップ
| # | 列 | カラム名 | グループ | 備考 |
|---|---|---|---|---|
| 1 | A | 有効フラグ | 管理 | checkbox |
| 2 | B | 発注ID(ORD) | 管理 | ORD_YYYYMMDD_NNNN |
| 3 | C | 起票日時 | 記録 | yyyy-mm-dd hh:mm |
| 4 | D | 起票者 | 記録 | |
| 5 | E | 取引先名 | 誰に | pulldown |
| 6 | F | 契約・件名 | 何を | 自由入力 |
| 7 | G | 摘要 | 何を | 契約の補足情報 |
| 8 | H | 契約形態 | 何を | pulldown |
| 9 | I | 開始年月 | いつ | 新規 yyyy-mm |
| 10 | J | 終了年月 | いつ | 新規 yyyy-mm (空=無期限) |
| 11 | K | 税抜金額_発注 | いくら | #,##0 |
| 12 | L | 消費税額_発注 | いくら | #,##0 |
| 13 | M | 税込金額_発注 | いくら | #,##0 |
| 14 | N | 発注残高(自動計算) | いくら | #,##0 (Action Aで自動減算) |
| 15 | O | PJ名 | 補助 | pulldown |
| 16 | P | 発注ステータス | 補助 | pulldown |
| 17 | Q | 参照元区分 | 補助 | 新規 (HC/SaaS/CAPEX/Pipeline/Adhoc) |
| 18 | R | 参照元ID | 補助 | 新規 (EMP_0001等) |
| 19 | S | 証憑URL | 記録 |
参照元区分の値
| 値 | ソースタブ | 参照元IDの例 |
|---|---|---|
| HC | 22_bud_headcount | EMP_0001 |
| SaaS | 23_bud_subscription | SUB_0001 |
| CAPEX | 24_bud_capex_loan | CPX_0001 |
| Pipeline | 21_bud_pipeline | PIP_0001 |
| Adhoc | 25_bud_adhoc | ADH_0001 |
ソース別の開始年月・終了年月
| ソース | 開始年月 | 終了年月 |
|---|---|---|
| HC | 22の開始年月 | 22の終了年月 (空なら適用年度末 {年度+1}-03) |
| SaaS | 23の開始・契約年月 | 23の次回更新・終了年月 |
| CAPEX | 24の会社支払開始年月 | 開始 + 返済月数 − 1 |
| Pipeline | 21の計上開始年月 | 開始 + 継続月数 − 1 |
| Adhoc | 25の発生日(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_ID | ORD_{yyyyMMdd}_{NNNN} (自動発番) |
| 起票者 | RPA自動起票 |
| 発注ステータス | 発注済 |
| 取引先名 | HC の取引先名 (空なら氏名) |
| PJ名 | 指定なし_共通費など |
| 契約・件名 | {氏名} {雇用形態} {適用年度}年度 |
| 契約形態 | HC の雇用形態 |
| 開始年月 | HC の開始年月 |
| 終了年月 | HC の終了年月 (空なら適用年度末 {適用年度+1}-03) |
| 参照元区分 | HC |
| 参照元ID | HC の管理ID (例: EMP_0001) |
| 税抜金額_発注 | (月額給与 − 源泉消費税) × 契約月数 |
| 消費税額_発注 | 源泉消費税額_発注 × 契約月数 |
| 税込金額_発注 | 月額給与 × 契約月数 |
| 発注残高 | 税込金額_発注 と同額 (初期値) |
| 摘要 | 【RPA:HC】{適用年度}年度 {氏名} 年間契約 |
契約月数の算出: 開始年月〜終了年月の月数(終了月を含む)。
例: 2025-11 〜 2026-03 → (2026-2025)×12 + (3-11) + 1 = 5ヶ月
終了年月が未設定の場合は {適用年度+1}-03 をフォールバック適用後に計算。
ORD検索・作成ロジック(マトリクス)
| STEP | 処理 | 入力(物理名: タブ.列) | 処理詳細 / 変換ロジック | 出力(物理名: タブ.列) | 例外処理 |
|---|---|---|---|---|---|
| O1.1 | ORDマップ構築 | 31_wrk_order.S,I列 (参照元ID, 開始年月) | 有効行を参照元ID + "|" + parseDateToYm(開始年月)でMap化 | 変数: ordMap { key: ordId } | — |
| O1.2 | ORDキー生成 | 22_bud_headcount.B,J列 (管理ID, 開始年月) | ordKey = 管理ID + "|" + 開始年月 | 変数: ordKey | — |
| O1.3 | ORD検索 | 変数: ordMap | ordMap内に存在 → 既存ordIdを使用 | 変数: ordId | — |
| O1.4 | ORD新規作成 | ordKey不存在時 | generateOrdId_() で発番、buildOrdRow_() で行構築。参照元区分="HC", 参照元ID=管理ID | 31_wrk_order (新規行) | — |
| O1.5 | INV紐づけ | 変数: ordId | 全INV Row (1,1b,2b,2,3,4,5) に 親発注ID(ORD) = ordId を設定 | 32_wrk_invoice.C列 | — |
| O1.6 | 一括書き込み | 変数: newOrdRows | writeOrdRows_() で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.js | WRK_ORDR headers リニューアル(19 列) | §3.2.3 |
101_sys_config.js | BUD_SUBS / BUD_PIPE のキー列名を「管理 ID」に統一 | §3.2.3 |
401_bat_rpa.js | ORD ヘルパー 4 関数追加 | §3.2.1 |
401_bat_rpa.js | generateHcInvoices に ORD 検索/作成 + 親発注 ID 設定 | §3.2.1 |
403_subledger_engine.js | ORD 列参照をヘッダー名ベース化 | §3.2.4 |
§3.2.1 詳細関数:
generateOrdId_/buildOrdRow_/writeOrdRows_/buildOrdMap_
5. テスト仕様
| テストID | テスト名 | 前提条件 | 期待結果 |
|---|---|---|---|
| T1 | DDL実行 | setupAllSchemas実行 | 31_wrk_order に新列(I〜J:年月, Q:参照元区分, R:参照元ID)が追加される |
| T2 | HC起票 (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のみ追加 |
| T5 | Action A 実行 | ORD・INVが存在する状態でAction A | ORD発注残高 (N列) が INV請求総額分だけ減算される |
| T6 | 2人分同時起票 | 22_bud_headcountに有効行2行 | ORD 2行 + INV 各人分が正しく紐づく |
| T7 | 年度またぎ | 同一従業員で開始年月が異なる2行 | 開始年月が異なれば別ORDが作成される |
付録A: 将来拡張(Phase 2以降)
| Phase | ソース | ORD粒度 | 参照元区分 | 参照元ID | 開始年月 | 終了年月 |
|---|---|---|---|---|---|---|
| 2 | SaaS | 契約1件 | SaaS | SUB_NNNN | 開始・契約年月 | 次回更新・終了年月 |
| 3 | CAPEX | 借入1件 | CAPEX | CPX_NNNN | 会社支払開始年月 | 開始 + 返済月数 − 1 |
| 4 | Pipeline | 案件1件 | Pipeline | PIP_NNNN | 計上開始年月 | 開始 + 継続月数 − 1 |
| 5 | Adhoc | 申請1件 | Adhoc | ADH_NNNN | 発生日(P/L計上日) | 同月 |