MAS-087: 元データ修正→下流タブ再同期 (RPA再生成)
概要
| 項目 | 内容 |
|---|---|
| 案件ID | MAS-087 |
| カテゴリ | データ再同期 / UI |
| Phase | P2 |
| 優先度 | ★ |
| 所要時間 | 3〜4時間 |
| 対象ファイル | 300_ui/301_ui_assist.js(新規関数追加)、templates/operations_sidebar.html(ボタン追加) |
| 前提案件 | なし(独立着手可能) |
目的
ユーザーが 20 番台予算タブ(21_bud_pipeline / 22_bud_headcount / 23_bud_subscription / 24_bud_capex_loan)の元データを修正した際に、対応する 32_wrk_invoice の INV レコードを手動で再生成できる UI を提供する。
- 現状の運用: 元データ修正後に INV を修正する公式手順が存在せず、ユーザーが手動で INV 行を削除し RPA を再実行する必要がある。
- 本案件のスコープ: 選択行の元データに紐づく有効 INV を論理削除(
有効フラグ=FALSE)し、対象シートの RPA を再実行することで INV を再生成する UI を提供する。 - スコープ外:
42_trn_journal(自動仕訳)への反映。既発行 JNL の取り消しは監査上の重要操作のため、本案件では対応せず、ユーザーが別途 Action A(processInvoiceApprovals)を再実行する運用とする。
現在のコード
RPA 公開 API の実シグネチャ(全て「シート全体」対象・行単位呼び出し不可)
Phase 1 で 400_domain/40x_rpa_*.js を確認した結果:
| 関数名 | 対象シート | シグネチャ | 行単位呼び出し |
|---|---|---|---|
generatePipelineInvoices(targetOverride, _silent) | 21_bud_pipeline | targetOverride は対象年月("YYYY-MM")。行単位フィルタ引数なし | × |
generateHcInvoices(targetOverride, _silent) | 22_bud_headcount | 同上 | × |
generateSaasInvoices(targetOverride, _silent) | 23_bud_subscription | 同上 | × |
generateCapexInvoices(targetOverride, _silent) | 24_bud_capex_loan | 同上 | × |
いずれもシート全体を走査し、RpaCommon による冪等性チェック(既存 INV は二重起票されない)で重複生成を防ぐ。単一行のみを対象とする API は存在しない。
参照経路(予算ID → INV)
000_infra/003_contracts.js 確認結果:
OrderDTO—参照元区分("SUB"/"HC"/"CAPEX"/"PIPELINE" 等)と参照元ID(PIP_xxxx/EMP_xxxx/SUB_xxxx/CPX_xxxx)を保持するInvoiceDTO—親発注ID(ORD)を保持する。予算ID を直接保持するフィールドは持たない
したがって予算ID → INV は 2 ステップ検索 が必要:
予算ID (PIP_xxxx 等)
↓ OrderRepository.findAll() で 参照元ID が一致する有効 ORD を取得
ORD_YYYYMMDD_NNNN
↓ InvoiceRepository.findAll() で 親発注ID(ORD) が一致する有効 INV を取得
INV_YYYYMMDD_NNNN
InvoiceDTO の主要フィールド(003_contracts.js L40-67)
有効フラグ: boolean(論理削除フィールド)請求ステータス:"未処理" | "承認済" | "却下"の 3 値のみ。"完了"は存在しない自動仕訳JNL_ID: 値があれば Action A で仕訳発行済み
UI エントリ(templates/operations_sidebar.html)
現行では onOpen() から起動する「🚀 BizLP 操作パネル」サイドバーに全操作が集約されている(101_sys_config.js L299-321)。新規操作ボタンは operations_sidebar.html に <button class="btn"> タグで追加する方式。
既存セクション:
- 📒 経理業務 (RPA / Action)
- 🔍 消込・マッチング
- 📝 費用登録
- 📊 マート更新
- ⚙️ メンテナンス
- 🔧 開発・設定
- 🔧 マイグレーション
本案件の再同期ボタンは ⚙️ メンテナンス セクションに配置する(運用フローとしては「データ整合性チェック」の延長に位置するため)。
Repository の副作用(200_data/202_repository.js L152-207)
InvoiceRepository.findAll()は{ headers, dtos }を返すInvoiceRepository.save(dtos)は 全置換。取得した全 DTO 配列を保持したまま対象だけ更新して渡す必要があるOrderRepository.findAll()/.save(dtos)も同パターン
修正方針
処理フロー(7 ステップ)
- ユーザー操作: 20 番台予算シート(
21_bud_pipeline/22_bud_headcount/23_bud_subscription/24_bud_capex_loan)で再生成したい行を選択した状態で、サイドバー「⚙️ メンテナンス」セクションの 「🔁 INV 再同期(選択行)」 ボタンをクリックする。 - ソース種別判定: 現在のアクティブシート名で分岐する。
21_bud_pipeline→ Pipeline、22_bud_headcount→ HC、23_bud_subscription→ Subscription、24_bud_capex_loan→ Capex。それ以外のシートで実行された場合は Toast「このメニューは 20 番台予算シートから実行してください。」で終了。 - 予算ID取得: 選択範囲の各行について、ヘッダー名ベースで
管理ID列をindexOfで特定し、値(PIP_xxxx/EMP_xxxx/SUB_xxxx/CPX_xxxx)を取得する。空の行はスキップ。 - INV検索:
OrderRepository.findAll()で全 ORD を取得し、参照元IDが手順3 の予算ID と一致する有効 ORD の発注ID(ORD)を収集する。次にInvoiceRepository.findAll()で全 INV を取得し、親発注ID(ORD)が手順3 で集めた ORD ID セットに含まれる かつ有効フラグ === trueの INV を対象候補とする。 - (Human-in-the-Loop)確認ダイアログ: 対象候補 INV 一覧(INV ID、発生日、金額、請求ステータス)を整形し
SpreadsheetApp.getUi().alert(OK_CANCEL)で表示する。件数が 0 件の場合は「既存の請求レコードが見つかりませんでした。新規に生成しますか?」ダイアログに切り替え、「はい」なら論理削除ステップをスキップして手順6 に進む。候補に請求ステータス !== '未処理'(="承認済"または"却下")または自動仕訳JNL_ID非空の INV が 1 件でも含まれる場合はブロックし「決済処理済または承認済の請求レコードが含まれるため再同期できません。経理担当者に確認してください。」ダイアログを表示して終了。 - 論理削除→RPA再実行: 承認後、対象 INV の
有効フラグをfalseに設定した DTO 配列をInvoiceRepository.save(allDtos)で全置換書き込み。各 INV についてUtils.auditLog('DELETE', '32_wrk_invoice', invId, '有効フラグ', 'resyncInvoiceFromSource', true, false, 'S-15再同期')を呼ぶ。続いてソース種別に応じた RPA 関数(手順2 で判定済み)を 引数なし で呼び出す(generatePipelineInvoices()等)。RPA はシート全体を走査するがRpaCommonの冪等性チェックで既存有効 INV は二重起票されず、論理削除した INV の分だけが新規生成される。 - 結果通知:
Utils.toastResult('resyncInvoiceFromSource', '論理削除: N件 / 再生成: M件')で処理結果を通知する。
二重実行防止(LockService)
LockService.getScriptLock() でスクリプトレベルの排他ロックを取得する。GAS の LockService はキーベースロックをサポートしないため、スクリプト全体のシングルロックとして機能する。
var lock = LockService.getScriptLock();
if (!lock.tryLock(10000)) {
SpreadsheetApp.getActiveSpreadsheet().toast(
'別の再同期処理が実行中です。しばらく待ってから再試行してください。',
'⚠️ 再同期', 5);
return;
}
try {
// 手順2〜7 の本体処理
} finally {
lock.releaseLock();
}
waitLock ではなく tryLock(10000) を採用する理由: 再同期は ユーザーが同期的に結果を待つ UI 操作 のため、タイムアウトまで待機されると UX が劣化する。10 秒で取得できなければ即エラーを返す。
影響範囲
- 変更ファイル:
300_ui/301_ui_assist.js— 新規関数resyncInvoiceFromSource()を追加(既存のパターンpadIdDigitsTo4/removePartnerAbbreviationsと同列)templates/operations_sidebar.html— 「⚙️ メンテナンス」セクションに<button>を 1 行追加
- 読み取りのみ:
400_domain/401_rpa_hc.js/402_rpa_subscription.js/403_rpa_capex.js/406_rpa_pipeline.js(既存関数を呼び出すのみ。改変しない) - スコープ外:
42_trn_journal(本案件では一切変更しない) - 影響する下流: 論理削除した INV は
32_wrk_invoiceに残る(物理削除ではなく有効フラグ=FALSE)。マート更新や Action A/B は有効フラグ=TRUEの行のみ対象のため、論理削除後は下流に波及しない
注意事項
InvoiceRepository.save()は全置換。findAll()で取得した全 DTO 配列を保持し、対象 INV のみ有効フラグ = falseに変更してからsave()に渡すこと。フィルタした部分配列を渡すと対象外 INV が消失する- 既存 RPA 関数は改変しない。全て「シート全体」対象で行単位呼び出しできないが、
RpaCommonの冪等性チェックで既存有効 INV は二重起票されないため、そのまま引数なしで呼び出せば論理削除分のみ再生成される - 予算ID → INV の経路は 2 ステップ必須。
InvoiceDTOは参照元IDを直接保持しない。OrderRepository.findAll()→ 該当 ORD ID 収集 →InvoiceRepository.findAll()→親発注ID(ORD)でフィルタ の順序 Utils.auditLog()は例外を握りつぶす。98_audit_logがsetupAllSchemasで作成済みであることが前提(CLAUDE.md /003_contracts.jsに記載)。未作成時は console.error のみで処理継続- サイドバーはグローバル UI。シート限定ボタンは実現不可のため、ボタン実行時にアクティブシートを判定してガードする(Step 2 のソース種別判定がそのガード役を兼ねる)
請求ステータスの有効値は 3 値のみ("未処理"|"承認済"|"却下")。過去の設計書や Gemini 生成コードで"完了"が登場する場合があるが実装上は存在しないため参照しないこと- ロック取得失敗時は
releaseLock()を呼ばない。tryLockが false を返した場合はそもそもロックを取得していないため、finallyブロック外で早期 return する
エッジケース
| 条件 | 振る舞い | 理由 |
|---|---|---|
| 対象行が未選択(シート全体が選択状態 / 範囲が1行目のヘッダーを含む) | Toast「再同期の対象行を選択してください。」で終了 | 選択範囲の行数が全行と一致する場合などを含め、意図しない全件処理を防ぐ |
選択行の 管理ID 列が空 | その行はスキップ。全行が空なら Toast「管理ID が空の行しかありません。」で終了 | 未発番の予算行を対象にしても参照経路をたどれないため |
| 選択行に紐づく有効 INV レコードが 0 件 | 「既存の請求レコードが見つかりませんでした。新規に生成しますか?」ダイアログ確認 → 「はい」で論理削除ステップをスキップして RPA 再実行のみ実施 | 初回生成失敗後のリカバリ操作を想定 |
紐づく INV レコードの 請求ステータス に "未処理" 以外("承認済" または "却下")が含まれる | 処理をブロックし「決済処理済または承認済の請求レコードが含まれるため再同期できません。経理担当者に確認してください。」ダイアログを表示 | InvoiceDTO.請求ステータス の有効値は "未処理"|"承認済"|"却下" の 3 値のみ("完了" は存在しない)。承認済データの誤変更防止 |
紐づく INV レコードの 自動仕訳JNL_ID が非空(= Action A で仕訳発行済み) | 上記と同様にブロック | 仕訳発行済みの INV を論理削除すると 42_trn_journal との整合性が崩れる。本案件スコープ外 |
| 20 番台以外のシートでボタンを実行(サイドバーはグローバル) | 「このメニューは 20 番台予算シート(21/22/23/24)から実行してください。」Toast で終了 | グローバル UI の誤操作防止 |
| LockService のロック取得タイムアウト(10 秒超) | 「別の再同期処理が実行中です。しばらく待ってから再試行してください。」Toast で終了。tryLock が false なのでロック解放呼び出しは不要 | スクリプトレベルロックのため別ユーザーの同時実行を防ぐ |
| RPA 関数の呼び出し中に例外発生 | Utils.logError() でスタックトレース記録。「再生成中にエラーが発生しました。ログを確認してください。」Toast。論理削除済みの INV は残ったままになるためその旨をダイアログで警告 | GAS にはトランザクションが存在しないため、中断時の状態を明示する |
| 対象 ORD が 0 件(予算ID に対応する ORD が未作成) | 上記「INV 0 件」と同じ扱いで新規生成確認ダイアログに進む | 予算を作成したが RPA 未実行の状態を想定 |
| 複数行選択で一部の行だけ INV が「承認済」を含む | 一つでも承認済があれば全体をブロック | 部分的な再同期は整合性判断を複雑化させるため、All-or-Nothing 方針 |
実データ検証
実装前に MCP または GAS コンソールで以下を確認する:
| 確認項目 | 確認方法 | 理由 |
|---|---|---|
32_wrk_invoice のヘッダーに 有効フラグ / 親発注ID(ORD) / 請求ステータス / 自動仕訳JNL_ID の実列名と位置 | GAS エディタで =INDIRECT("32_wrk_invoice!1:1") または MCP read_range でヘッダー行を取得 | 列名ハードコード禁止のため indexOf で動的取得することを前提とするが、そもそも実在するかの事前確認 |
31_wrk_order の 参照元区分 / 参照元ID カラムに PIP_xxxx / EMP_xxxx / SUB_xxxx / CPX_xxxx 形式のデータが実際に格納されているか | MCP read_range で 31 タブの該当列をサンプリング | 2 ステップ検索の前提となるデータ形式の確認 |
20 番台予算タブの 管理ID 列名が全 4 シートで同一(管理ID)か | 4 シートの 1 行目をそれぞれ確認 | ソース種別ごとに列名が異なるとロジックが複雑化する |
関連ドキュメント
| 仕様書 / ファイル | 関連箇所 |
|---|---|
| CLAUDE.md | コーディング規約(列参照はヘッダー名ベース、有効フラグ=FALSE 行は処理スキップ、Human-in-the-Loop 原則) |
| 003_contracts.js | L15-36: OrderDTO(参照元区分・参照元ID)、L40-67: InvoiceDTO(親発注ID(ORD)・有効フラグ・請求ステータス) |
| 202_repository.js | L107-147: OrderRepository、L152-207: InvoiceRepository(findAll/save は全置換) |
| 407_rpa_orchestrator.js | RPAService の公開 API(本案件は既存関数を直接呼ぶ) |
| 406_rpa_pipeline.js | L10: generatePipelineInvoices(targetOverride, _silent) シグネチャ |
| 401_rpa_hc.js | L10: generateHcInvoices(targetOverride, _silent) シグネチャ |
| templates/operations_sidebar.html | ⚙️ メンテナンスセクション(新規ボタンの追加先) |
| dev_mas-179_audit_trail.md | Utils.auditLog() の仕様(98_audit_log 未作成時は握りつぶす) |
人間が検討すべき事項
- 再同期の範囲(TODO_future.md から転記): 「全件再生成 vs 差分更新」の方針決定。本仕様書では 「論理削除 + 全件再生成(RPA 冪等性に依拠)」 を採用する。理由:
- 差分更新はフィールド単位の比較ロジックが複雑化し、比較もれ・不整合リスクが高い
- 全件再生成は既存 RPA 関数(
RpaCommonの冪等性チェック付き)をそのまま再利用でき、追加の実装コストが最小 - 20 番台予算行 1 件あたりの INV 生成件数は月数×科目数程度(多くても数十件)でパフォーマンス問題が生じにくい
42_trn_journal(自動仕訳)をスコープに含めるか: 含めない。既発行 JNL の取り消しは監査上の重要操作で Human-in-the-Loop 承認フローを別途設計する必要がある。本案件ではユーザーが「INV 再同期 → Action A 再実行」を順次手動で行う運用で割り切る。将来的に JNL 再同期を自動化する場合は別案件化- 複数行選択時の All-or-Nothing 方針の妥当性: 「一部承認済」の場合に「承認済以外だけ再同期する」オプションをユーザーが求める可能性がある。初版は安全側に倒し全体ブロックとするが、運用してニーズが出たら再検討
- サイドバーの配置場所: 「⚙️ メンテナンス」セクションに配置。別案として「🔧 開発・設定」や新規セクション「🔁 データ再同期」も検討したが、運用者(非エンジニア)が日常的に触る操作のため目立つ位置が望ましく「メンテナンス」下とした
実装プロンプト(Claude Code 用)
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-087「元データ修正→下流タブ再同期 (RPA再生成)」を実装してください。
## 実行前タスク
- `100_config/101_sys_config.js` を Read し、`onOpen()` とサイドバー起動の仕組み(`openOperationsSidebar()`)を確認する
- `templates/operations_sidebar.html` を Read し、「⚙️ メンテナンス」セクションのボタン追加パターンを確認する
- `400_domain/407_rpa_orchestrator.js` を Read し、RPAService の公開 API シグネチャ(本案件では `RPAService.generatePipeline()` 等ではなく、各実関数 `generatePipelineInvoices()` / `generateHcInvoices()` / `generateSaasInvoices()` / `generateCapexInvoices()` を直接呼ぶ)を確認する
- `400_domain/406_rpa_pipeline.js` / `401_rpa_hc.js` / `402_rpa_subscription.js` / `403_rpa_capex.js` を Read し、いずれも `(targetOverride, _silent)` シグネチャで「シート全体」を対象とすることを確認する
- `000_infra/003_contracts.js` を Read し、`OrderDTO.参照元ID` / `OrderDTO.参照元区分` / `OrderDTO.発注ID(ORD)` / `InvoiceDTO.親発注ID(ORD)` / `InvoiceDTO.有効フラグ` / `InvoiceDTO.請求ステータス`(`"未処理"|"承認済"|"却下"`)/ `InvoiceDTO.自動仕訳JNL_ID` のフィールド名を確認する
- `200_data/202_repository.js` を Read し、`OrderRepository.findAll()` / `InvoiceRepository.findAll()` が `{headers, dtos}` を返し、`save(dtos)` が全置換であることを確認する
- `300_ui/301_ui_assist.js` を Read し、`padIdDigitsTo4()` / `removePartnerAbbreviations()` など既存 UI エントリポイントの実装パターンを確認する
## 修正対象ファイル
- `300_ui/301_ui_assist.js` — 新規関数 `resyncInvoiceFromSource()` をファイル末尾に追加
- `templates/operations_sidebar.html` — 「⚙️ メンテナンス」セクションに `<button class="btn" onclick="run('resyncInvoiceFromSource', this)">🔁 INV 再同期(選択行)</button>` を追加
## 実装内容
エントリポイント関数: `function resyncInvoiceFromSource()`(サイドバーから google.script.run 経由で呼ばれる)
1. `LockService.getScriptLock()` で排他ロックを取得。`lock.tryLock(10000)` が false なら Toast 通知して return(`releaseLock` は呼ばない)
2. `try { ... } finally { lock.releaseLock(); }` で本体をラップ
3. アクティブシート名を取得。`21_bud_pipeline` / `22_bud_headcount` / `23_bud_subscription` / `24_bud_capex_loan` 以外なら Toast「このメニューは 20 番台予算シート(21/22/23/24)から実行してください。」で return
4. シート名から RPA 関数を選択: pipeline → `generatePipelineInvoices`, headcount → `generateHcInvoices`, subscription → `generateSaasInvoices`, capex_loan → `generateCapexInvoices`
5. `SpreadsheetApp.getActiveRange()` で選択範囲を取得。範囲の行番号が 1(ヘッダー行のみ)または行数がシート最終行と一致する場合は「再同期の対象行を選択してください。」Toast で return
6. 選択範囲の各行について、ヘッダー名 `管理ID` を `indexOf` で特定し値を収集。空なら個別にスキップ。全行空なら Toast で return
7. `OrderRepository.findAll()` で全 ORD を取得し、`有効フラグ === true` かつ `参照元ID` が手順6 の予算 ID セットに含まれる ORD の `発注ID(ORD)` を集める
8. `InvoiceRepository.findAll()` で全 INV を取得し、`有効フラグ === true` かつ `親発注ID(ORD)` が手順7 の ORD ID セットに含まれる INV を対象候補とする
9. 対象候補が 0 件の場合、`ui.alert('再同期確認', '既存の請求レコードが見つかりませんでした。新規に生成しますか?', OK_CANCEL)` で確認。OK なら手順11 へ、Cancel なら return
10. 対象候補に `請求ステータス !== '未処理'` または `自動仕訳JNL_ID` 非空の INV が 1 件でもあれば `ui.alert('❌ 再同期不可', '決済処理済または承認済の請求レコードが含まれるため再同期できません。経理担当者に確認してください。', OK)` を表示して return
11. 対象候補を整形した一覧(INV ID / 発生日 / 税込金額_計画 / 請求ステータス)を文字列化し `ui.alert('🔁 INV再同期確認', '以下のINVを論理削除し再生成します:\\n\\n' + list, OK_CANCEL)` で確認。Cancel なら return
12. 対象 INV の `有効フラグ` を `false` に設定した DTO 配列全体を `InvoiceRepository.save(allDtos)` で書き戻す。**対象外を含む全 DTO を保持し、対象のみ変更すること**
13. 各論理削除 INV について `Utils.auditLog('DELETE', '32_wrk_invoice', invId, '有効フラグ', 'resyncInvoiceFromSource', true, false, 'S-15再同期')` を呼ぶ
14. 手順4 で選択した RPA 関数を **引数なし** で呼び出す(例: `generatePipelineInvoices()`)
15. RPA 呼び出し後の有効 INV 件数と論理削除件数を比較し、`Utils.toastResult('resyncInvoiceFromSource', '論理削除: N件 / 再生成: M件')` で通知
## 制約
- 既存の RPA 関数(`400_domain/40x_rpa_*.js`)のロジックは改変しない。呼び出しのみ
- `InvoiceRepository.save()` は全置換のため、`findAll()` で取得した全 DTO を保持して部分更新する
- 列番号ハードコード禁止。ヘッダー名ベースで列を参照する(CLAUDE.md 規約)
- `LockService.getScriptLock()` + `tryLock(10000)` + `try { ... } finally { lock.releaseLock() }` パターンを必ず使用する
- ブランチは `feat/S-15-invoice-resync` を切り PR → main マージのフローに従う
## エッジケース
仕様書「エッジケース」テーブルの全条件を実装に反映すること。特に:
- 選択行が未選択 / ヘッダー行のみ → Toast で return
- 全行の `管理ID` が空 → Toast で return
- 対象候補 0 件 → 新規生成確認ダイアログ
- 承認済・却下・仕訳発行済 INV を含む → ブロックダイアログ
- 20 番台以外のシート → Toast で return
- ロック取得タイムアウト → Toast で return(releaseLock 不要)
- RPA 例外 → `Utils.logError()` + 警告ダイアログ
## 動作確認
1. `npm run push:dev` で開発環境にデプロイ
2. スプレッドシートを再読み込みし、サイドバー「⚙️ メンテナンス」に「🔁 INV 再同期(選択行)」ボタンが表示されていることを確認
3. `21_bud_pipeline` を開き、有効な PIP_xxxx 行を 1 行選択してボタン実行 → 確認ダイアログに対象 INV が列挙されることを確認
4. OK 承認後、`32_wrk_invoice` で対象 INV の `有効フラグ` が FALSE になり、末尾に新規 INV が追加されていることを確認
5. `98_audit_log` に `DELETE / 32_wrk_invoice / INV_xxxx / 有効フラグ / resyncInvoiceFromSource` のレコードが記録されていることを確認
6. ヘッダー行のみ選択した状態でボタンを実行し、Toast「再同期の対象行を選択してください。」が表示されて処理が終了することを確認
7. `請求ステータス = 承認済` の INV に紐づく行を選択してボタン実行し、ブロックダイアログが表示されることを確認
8. `自動仕訳JNL_ID` 非空の INV に紐づく行でも同様にブロックされることを確認
9. `22_bud_headcount` / `23_bud_subscription` / `24_bud_capex_loan` でも同じ挙動になることを確認
10. `21_bud_pipeline` 以外の一般シート(例: `91_fs_bs`)でボタンを実行し、Toast「このメニューは 20 番台予算シート(21/22/23/24)から実行してください。」が表示されることを確認
### 拡張思考の使用状況
| フェーズ | 拡張思考 | 備考 |
|---------|:--------:|------|
| 実行前タスク(ファイル調査・関数名確認) | あり | ORD 経由の 2 ステップ参照経路の確定に使用 |
| 実装(コード記述) | なし | 仕様書でフロー・エッジケースが確定済み |
推奨実行モデル
| 工程 | 推奨モデル | 理由 |
|---|---|---|
| 仕様書作成(本ドキュメント) | Claude Opus 4.7 | 複数 RPA ファイルの関数シグネチャ確認、ORD 経由の参照経路の設計判断が必要 |
| 実装(コード記述) | Claude Sonnet 4.6 | 既存パターン(301_ui_assist.js の UI エントリ、LockService 定型)の適用と複数ファイル変更が必要 |
| 動作確認 | ユーザー手動 | GAS エディタ / スプレッドシートでの UI 操作、承認済 INV のモック準備が必要 |
変更履歴
| 日付 | 変更内容 |
|---|---|
| 2026-04-19 | 初版作成 |
仕様書作成プロンプト
仕様書作成プロンプト(展開して表示)
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】
1. **拡張思考の使い分け**: Phase 1(設計)では拡張思考をフル活用し、ファイル名形式・エッジケース一覧・Step 分割粒度・固有名詞(関数名/シート名/列名/行番号)を完全に確定させる。Phase 2(清書)の各 Step 内では拡張思考を最小限に抑え、Phase 1 で確定済みの内容の書き下しに徹する。出力途中で再考しない。
2. **テキスト報告の禁止**: 「〜を作成します」等の text のみで tool_use なしに turn を終了しない。説明は 1 文以内。直ちに tool を呼ぶ。
3. **4-5 分割の Write/Edit 実行**: 仕様書作成は Step 2-1〜2-4 に分けて実行する(詳細は各 Step 参照)。1 回の Write/Edit は約 300 行以内を目安にする。
4. **各 Step で何を書くかを具体指示**: 設計判断を Phase 2 実行時に持ち込まない。Phase 1 で固有名詞・行番号・関数名をすべて確定させてから清書に入る。
======================================================================
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。
案件 S-15「元データ修正→下流タブ再同期 (RPA再生成)」の開発仕様書を作成してください。
仕様書新規作成後は `docs/_config.json` の `nav` 配列の適切なセクションに必ず追記してください。
---
## Phase 1: 実行前タスク(テキスト報告禁止。即座にツール実行)
以下のファイルを順に Read し、確認すべきポイントを全て Phase 1 中に解決してから Phase 2 に進むこと。**Grep は「どこにあるか」の発見まで。「どう書くか」の判断は必ず Read で行う。**
### 1-A: 案件要件の把握
- `docs/_internal/TODO_future.md` — S-15 の案件名・概要・人間が検討すべき事項を取得する
### 1-B: 既存仕様書テンプレートの把握
- `docs/dev/dev_mas-094_boundary_month_selector.md` などの UI/メニュー系仕様書を 1 件 Read し、フォーマットを把握する
### 1-C: メニュー定義の確認(固有名詞の裏取り)
- `100_config/101_sys_config.js` を Read し、`onOpen()` の `ui.createMenu()` 呼び出し部分で**実在するメニュー名・サブメニュー名の文字列**を確認する。動作確認手順に書く固有名詞はここから引用する。仕様書に「🔧 ○○」と書く場合は必ずこのファイルで実在を確認すること
### 1-D: RPA 公開 API・実関数名の確認(ハルシネーション防止)
以下のファイルを Read し、各予算シートに対応する**実際の関数名**を確認する。Gemini が生成した `createInvoicesFromPipeline_` 等の関数名は未検証のため、実在する関数名に差し替えること。
- `400_domain/407_rpa_orchestrator.js` — `RPAService` の公開 API 一覧(`runHC`/`runPipeline`/`runSubscription`/`runCapex` 等の実際のシグネチャ)
- `400_domain/406_rpa_pipeline.js` — PIP_ 対応の内部 RPA 関数名と引数形式
- `400_domain/401_rpa_hc.js` — EMP_ 対応の内部 RPA 関数名と引数形式
- `400_domain/402_rpa_subscription.js` — SUB_ 対応の内部 RPA 関数名と引数形式
- `400_domain/403_rpa_capex.js` — CPX_ 対応の内部 RPA 関数名と引数形式
- 確認すべき点: 各関数は「1行分のデータ」を引数に取るか、「シート全体」を対象とするか。行単位で呼び出せない場合は設計変更が必要
### 1-E: InvoiceDTO・OrderDTO のフィールド定義確認(参照関係の正確な把握)
- `000_infra/003_contracts.js` を Read し、以下を確認する:
- `InvoiceDTO` に `有効フラグ` フィールドが存在するか(typedef に明示されていない。実シートに列があるかは `101_sys_config.js` の DDL 定義も参照して確認)
- `InvoiceDTO` に `参照元ID` フィールドが存在するか(`OrderDTO` には `参照元ID` があるが `InvoiceDTO` には記載なし。予算ID→INV の連鎖は「予算ID → `OrderDTO.参照元ID` → `InvoiceDTO.親発注ID(ORD)`」の2ステップ経路が想定されるが、実際の列構造を確認する)
- `InvoiceDTO.請求ステータス` の有効な値: `003_contracts.js` の typedef より `"未処理" | "承認済" | "却下"` の3値のみ(「完了」は存在しない)
### 1-F: Repository インターフェース確認
- `200_data/202_repository.js` を Read し、`InvoiceRepository.findAll()` / `InvoiceRepository.save()` の返却型と副作用(`save` は全置換であることを確認)を把握する
### 1-G: 新規関数の配置先を決定
- `300_ui/301_ui_assist.js` を Read し、UI トリガー関数の配置パターンを確認する。S-15 の新規関数(メニュー実行エントリポイント)をこのファイルに追加するか、新規ファイルを起こすかを Phase 1 中に決定する
---
## Phase 2: 仕様書の分割作成
出力先: `docs/dev/dev_mas-087_data_resync.md`
(Step 2-1〜2-4 の詳細は原プロンプト参照)
---
## Phase 3: `_config.json` への追記と構文チェック
1. `docs/_config.json` の `nav` 配列の **§E.2(バグ修正・バリデーション系)** セクションに以下を追記する
2. `docs/_config.json` の JSON 構文が壊れていないことを確認する
3. `docs/_internal/changelog.md` の先頭行に追記する
4. コミット→ push