最終更新: 2026/06/22 18:56
MAS-080: 21タブ管理IDの早期採番
概要
| 項目 | 内容 |
|---|---|
| 案件ID | MAS-080 |
| カテゴリ | パイプライン |
| Phase | P1 |
| 優先度 | ★★★ |
| 所要時間 | 30分 |
| 対象ファイル | 300_ui/301_ui_assist.js |
目的
受注前の案件にも管理ID(PIP_NNNN)を自動採番し、案件トラッキングを強化する。現状、管理IDはパイプラインRPA(generatePipelineInvoices)実行時に初めて採番されるため、受注確定前の案件にはIDがなく、他タブからの参照やトレーサビリティが確保できない。
発見事項: generateNextIdForAssist_() の未定義
調査の結果、301_ui_assist.js で7箇所から呼ばれている generateNextIdForAssist_() 関数がどのファイルにも定義されていないことが判明した。
| 行 | 呼び出し箇所 | プレフィックス |
|---|---|---|
| 28 | 16_wrk_master | REQ_ |
| 57 | 70_bud_resource | RSC_ |
| 63 | 23_bud_subscription | SUB_ |
| 100 | 31_wrk_order | ORD_ |
| 129 | 32_wrk_invoice | INV_ |
| 215 | 33_wrk_bank (INV入力) | STL_ |
| 224 | 33_wrk_bank (金額入力) | STL_ |
これらの呼び出しは全て onEdit トリガー経由で、現在ランタイムエラー(ReferenceError)が発生する状態にある。MAS-080の実装として、まずこの関数を定義し、その上で21タブの採番を追加する。
現在のコード
21タブの onEdit 処理(301_ui_assist.js L243-248)
} else if (sName.includes('21_bud_pipeline')) {
if (colName === '契約形態') {
// 継続月数/MRRの表示制御のみ。ID採番なし
}
}
パイプラインRPAでの既存採番ロジック(401_bat_rpa.js L1831-1882)
// 最大番号をスキャン
var mgrIdMax = 0;
for (var m = 1; m < pipeData.length; m++) {
var mid = String(pipeData[m][idxMgrId]).trim();
if (mid.startsWith('PIP_')) {
var num = parseInt(mid.replace('PIP_', ''), 10);
if (!isNaN(num) && num > mgrIdMax) mgrIdMax = num;
}
}
// 空なら採番
if (!pipeMgrId) {
mgrIdMax++;
pipeMgrId = 'PIP_' + String(mgrIdMax).padStart(4, '0');
}
ID_PREFIX_MAP の21タブ定義(002_constants.js)
{ pattern: '21_bud_pipeline', prefix: 'PIP_', digit: 4, isDate: false }
SHEET_DEFAULTS の21タブ初期値(002_constants.js)
{ pattern: '21_bud_pipeline', prefix: 'PIP_', defaults: {
'契約形態': 'スポット(狩猟)',
'売上科目': '売上高',
'確度(ヨミ)': 'Aヨミ (確度80%)',
'継続月数': 1,
'CF計上': '予算',
'入金ラグ(月)': 1,
'スポット売上・初期費用': 0,
'継続月額(MRR)': 0,
_dynamic: { '計上開始年月': 'nextYm' }
}}
修正方針
Step 1: generateNextIdForAssist_() の実装
301_ui_assist.js の末尾(またはヘルパー関数セクション)に追加。既存の7箇所の呼び出しを全て解決する汎用関数。
/**
* 指定シートのID列をスキャンし、次の管理IDを生成する
* @param {GoogleAppsScript.Spreadsheet.Sheet} sheet
* @param {string} prefix - IDプレフィックス ('PIP_', 'ORD_' 等)
* @param {number} idCol - ID列の1始まり列番号
* @param {number} digit - 連番の桁数 (通常4)
* @param {boolean} [isDate=false] - true なら 'PREFIX_YYYYMMDD_NNNN' 形式
* @returns {string} 次のID
*/
function generateNextIdForAssist_(sheet, prefix, idCol, digit, isDate) {
var data = sheet.getRange(2, idCol, sheet.getLastRow() - 1, 1).getValues();
var maxNum = 0;
var today = isDate ? Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyyMMdd') : '';
var searchPrefix = isDate ? prefix + today + '_' : prefix;
for (var i = 0; i < data.length; i++) {
var id = String(data[i][0]).trim();
if (id.startsWith(searchPrefix)) {
var numPart = id.substring(searchPrefix.length);
var num = parseInt(numPart, 10);
if (!isNaN(num) && num > maxNum) maxNum = num;
}
}
return searchPrefix + String(maxNum + 1).padStart(digit, '0');
}
Step 2: 21タブの onEdit 採番追加
L243-248 の既存処理を拡張し、「PJ・案件名」(C列) 入力時にID採番 + 初期値セットを追加。
} else if (sName.includes('21_bud_pipeline')) {
const idCell = sheet.getRange(row, 2); // B列: 管理ID
// S-08: PJ・案件名(C列)入力で管理ID早期採番
if (colName === 'PJ・案件名' && val && idCell.isBlank()) {
idCell.setValue(generateNextIdForAssist_(sheet, 'PIP_', 2, 4));
sheet.getRange(row, 1).setValue(true); // 有効フラグ
// SHEET_DEFAULTS の初期値を適用
setIfBlank('契約形態', 'スポット(狩猟)');
setIfBlank('売上科目', '売上高');
setIfBlank('確度(ヨミ)', 'Aヨミ (確度80%)');
setIfBlank('継続月数', 1);
setIfBlank('CF計上', '予算');
setIfBlank('入金ラグ(月)', 1);
setIfBlank('スポット売上・初期費用', 0);
setIfBlank('継続月額(MRR)', 0);
}
// 既存: 契約形態変更時の表示制御
if (colName === '契約形態') {
// ... (既存コードそのまま)
}
}
パイプラインRPAとの整合性
RPA(generatePipelineInvoices)は既に「管理IDが空なら採番」のロジックを持つ(L1831-1882)。MAS-080で onEdit 採番を追加すると、RPA実行時には既にIDが存在するため、RPAの採番ロジックはスキップされる。既存RPAコードの変更は不要。
影響範囲
- 変更ファイル:
301_ui_assist.jsのみ - Step 1:
generateNextIdForAssist_()関数追加(約20行)→ 既存7箇所の呼び出しが全て動作するようになる - Step 2: 21タブの onEdit ハンドラ拡張(約15行)
- 既存機能への影響: Step 1 は既存の壊れた呼び出しを修復するため、16/23/31/32/33/70タブのID自動採番が有効化される(現状は未定義エラーで無動作)
注意事項
setIfBlankヘルパーはhandleUxAssist内でローカル定義されている(L93付近)。21タブ処理からも参照可能か確認することgenerateNextIdForAssist_のisDateパラメータ: PIP_ はisDate: false(連番のみ)。ORD_/INV_/STL_ はisDate: true(日付+連番)sheet.getLastRow()が1(ヘッダーのみ)の場合のエッジケースに対応すること- RPAの既存採番ロジック(401_bat_rpa.js L1831-1882)は変更しない。onEdit で先に採番されていればRPA側はスキップする
関連ドキュメント
| 仕様書 | 関連箇所 |
|---|---|
| CLAUDE.md | シートへの書き込み位置は列B(ID列)で最終行を判定 |
人間が検討すべき事項
なし(UX改善。即実装可)
実装プロンプト(Claude Code 用)
Step 1: generateNextIdForAssist_() の実装
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 S-08 の Step 1 として、未定義の `generateNextIdForAssist_()` 関数を実装してください。
## 実行前タスク
以下のファイルを読み込んでください:
1. `300_ui/301_ui_assist.js` — 既存の7箇所の呼び出しパターン(L28, 57, 63, 100, 129, 215, 224)。引数の形式を全て確認
2. `000_infra/002_constants.js` — `Constants.ID_PREFIX_MAP` の定義。各エントリの `prefix`, `digit`, `isDate` を確認
3. `400_domain/401_bat_rpa.js` — L1831-1882の既存ID採番ロジック(参考実装)
4. `CLAUDE.md`
5. `docs/dev/dev_mas-080_pipeline_early_id.md`
## 修正対象ファイル
`300_ui/301_ui_assist.js` に関数を追加。
## 実装内容
`handleUxAssist` 関数の**外側**(ファイル末尾のヘルパーセクション)に `generateNextIdForAssist_()` を追加する。
**要件:**
- 引数: `(sheet, prefix, idCol, digit, isDate)`
- `sheet`: 対象シート
- `prefix`: IDプレフィックス('PIP_', 'ORD_' 等)
- `idCol`: ID列の1始まり列番号
- `digit`: 連番の桁数(通常4)
- `isDate`: true なら `PREFIX_YYYYMMDD_NNNN` 形式、false なら `PREFIX_NNNN` 形式
- ID列を全行スキャンし、該当プレフィックスの最大連番を取得
- isDate=true の場合、当日日付 `YYYYMMDD` をプレフィックスに含めてスキャン(同一日の最大値+1)
- `sheet.getLastRow()` が1以下(ヘッダーのみ)の場合は連番1を返す
**既存呼び出しとの整合性確認:**
| 呼び出し | prefix | idCol | digit | isDate |
|---------|--------|:-----:|:-----:|:------:|
| L28 (16_wrk_master) | REQ_ | 1 | 4 | true |
| L57 (70_bud_resource) | RSC_ | 2 | 4 | なし(=false) |
| L63 (23_bud_subscription) | SUB_ | 2 | 3 | なし(=false) |
| L100 (31_wrk_order) | ORD_ | 2 | 4 | true |
| L129 (32_wrk_invoice) | INV_ | 2 | 4 | true |
| L215, L224 (33_wrk_bank) | STL_ | 2 | 4 | true |
## 制約
- 既存の呼び出し箇所(7箇所)は変更しない
- 401_bat_rpa.js の採番ロジックも変更しない
- `isDate` パラメータが省略された場合は `false` として扱う
Step 2: 21タブ onEdit 採番追加
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 S-08 の Step 2 として、21_bud_pipeline の onEdit でPJ・案件名入力時に管理IDを自動採番する処理を追加してください。
## 実行前タスク
以下のファイルを読み込んでください:
1. `300_ui/301_ui_assist.js` — L243-248の既存21タブ処理、他タブのID採番パターン(L98-107のORD、L127-136のINV等)
2. `000_infra/002_constants.js` — `Constants.SHEET_DEFAULTS` の21タブ初期値定義
3. Step 1 で追加した `generateNextIdForAssist_()` のシグネチャ
4. `docs/dev/dev_mas-080_pipeline_early_id.md`
## 修正対象ファイル
`300_ui/301_ui_assist.js` の L243-248(21タブ処理セクション)を拡張。
## 実装内容
既存の `if (colName === '契約形態')` ブロックの**前**に、PJ・案件名入力時のID採番ブロックを追加:
1. `colName === 'PJ・案件名'` かつ値あり かつ `idCell.isBlank()` の場合:
- `generateNextIdForAssist_(sheet, 'PIP_', 2, 4)` でID採番
- 有効フラグ = true
- SHEET_DEFAULTS に定義された初期値をセット(setIfBlank使用)
2. `setIfBlank` ヘルパーが21タブ処理スコープから参照可能か確認。参照できない場合は、同スコープにidCellと同じパターンでsetIfBlankを定義
**初期値リスト(SHEET_DEFAULTS準拠):**
- 契約形態: 'スポット(狩猟)'
- 売上科目: '売上高'
- 確度(ヨミ): 'Aヨミ (確度80%)'
- 継続月数: 1
- CF計上: '予算'
- 入金ラグ(月): 1
- スポット売上・初期費用: 0
- 継続月額(MRR): 0
## 動作確認
`npm run push:dev` 後:
1. 21_bud_pipeline の C列(PJ・案件名)に新しい案件名を入力
2. B列に `PIP_0001` 等のIDが自動採番されること
3. A列(有効フラグ)が TRUE になること
4. 初期値(契約形態、売上科目等)がセットされること
5. 既にIDがある行でPJ・案件名を変更してもIDが上書きされないこと
### 拡張思考の使用状況
| フェーズ | 拡張思考 | 備考 |
|---------|:--------:|------|
| Step 1: generateNextIdForAssist_ 実装 | あり | isDate=true/false の分岐、日付フォーマット、エッジケース(空シート、連番溢れ)の考慮 |
| Step 2: 21タブ採番追加 | なし | 既存パターン(31/32タブ)の踏襲 |
推奨実行モデル
| 工程 | 推奨モデル | 理由 |
|---|---|---|
| 仕様書作成(本ドキュメント) | Claude Opus 4.6 | 未定義関数の発見と既存7呼び出しの整合性分析に高い推論力が必要 |
| Step 1 実装 | Claude Sonnet 4.6 | isDate=true/false の日付フォーマット分岐、7呼び出しとの整合性確認が必要 |
| Step 2 実装 | Claude Haiku 4.5 | 既存パターン(ORD/INV)の踏襲。判断要素が少ない |
変更履歴
| 日付 | 変更内容 |
|---|---|
| 2026-04-14 | 初版作成 |