# 承認図回覧(SiteId 492169) 回数採番ロジック改修 実装計画 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** ClassVの自動採番(`[ClassA]-[nnnn]`)に依存していた「回数」(ClassW)の算出方式を、同一マスターシート(ClassA)に紐づく有効な承認図回覧レコード数のカウント方式に置き換える。 **Architecture:** 既存の`$p.ex.hasPreviousApprovalReview`(同一ClassAで過去回覧の有無をboolean判定)を`$p.ex.getKairanCount`(件数=TotalCountを返す)へ拡張し、「再承認図回覧」ラベル判定と「回数」算出の両方に使い回す。カウントは新規作成時(ClassA選択完了時)に仮セット、プロセス実行時(回覧発行=Status100→300、再回覧=Status110→310)に確定再計算する2段構え。 **Tech Stack:** Pleasanterクライアントスクリプト(jQuery, `$p` API)。対象ファイルは`MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js`のみ。SiteSettings構造変更なし(ClassVの列削除はstaging側で対応済み、Ver5で確認済み)。 ## Global Constraints - 改修範囲はstaging環境(SiteId 492169)限定。production環境への反映は別フェーズ(本計画には含まない)。 - 回数カウント対象StatusはScreenshot確認済みの3値のみ: `["300","310","900"]`(保留910・取消920は除外)。 - 回数の表示形式は4桁ゼロ埋め文字列(例: `"0001"`)。旧ClassV由来の見た目を踏襲。 - 実装はクライアントスクリプト内で完結させる(`$p.apiGet`同期呼び出し、既存の`hasPreviousApprovalReview`/`getUsedFileGuids`と同じパターン)。サーバースクリプトは使わない。 - `$p.ex.getUsedFileGuids`のStatusフィルタも同様に`["300","310","900"]`へ変更する(今回のカウントロジックとは別関心事だが、ユーザー指示によりあわせて変更)。 - Pleasanterのクライアントスクリプトにはユニットテストの仕組みが無い。「テスト」はビルド→ドライラン差分確認→ユーザー承認→`--execute`反映→実ブラウザでの動作確認、というサイクルに読み替える。 --- ## File Structure - **Modify:** `MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js` - `$p.ex.hasPreviousApprovalReview`(354〜383行目)→ `$p.ex.getKairanCount`にリネーム・拡張(TotalCountを返す、Statusフィルタ変更) - `$p.ex.getMSSData`内(242〜244行目)→ 新関数呼び出しへの差し替え、ClassW仮セット追加 - `$p.ex.getUsedFileGuids`内(392〜397行目)→ Statusフィルタ変更のみ - `$p.ex.processScript`のcase '1'(642〜647行目)・case '10'(734〜739行目)→ 旧ClassV参照コード削除、`getKairanCount`での確定再計算に差し替え このファイル1本のみが対象。新規ファイル作成・SiteSettings構造変更(Columns/GridColumns等)は無い。 --- ### Task 1: `hasPreviousApprovalReview` を `getKairanCount` へ拡張 **Files:** - Modify: `MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js:354-383` **Interfaces:** - Consumes: なし(既存の`$p.apiGet`, `apiKey`グローバル変数を使用) - Produces: `$p.ex.getKairanCount(classA)` — 引数`classA`(マスターシートのResultId文字列)を受け取り、同一ClassAでStatus`["300","310","900"]`のレコード件数(Number)を返す。Task 2・Task 4がこの関数を呼び出す。 - [ ] **Step 1: 現在の関数を確認する** 対象は354〜383行目の以下のブロック(削除・置換対象であることの確認のみ、実際のRead済み内容を転記): ```js //同一マスターシート(classA)で過去に承認図回覧が発行済みかどうかを判定 $p.ex.hasPreviousApprovalReview = function (classA) { let hasPrevious = false; if (!classA) return hasPrevious; let view = { "ColumnFilterHash": { "ClassA": JSON.stringify([classA]), "Status": '["300","310","900","910","920"]' } }; $p.apiGet({ 'id': '492169', 'async': false, 'data': { 'ApiVersion': 1.1, 'ApiKey': apiKey, 'View': view }, 'done': function (data) { hasPrevious = data.Response.TotalCount > 0; }, 'fail': function (data) { console.log(data); } }); return hasPrevious; } ``` - [ ] **Step 2: 置き換える** 上記ブロックを丸ごと以下に置き換える(Editツールで`old_string`に上記全文、`new_string`に以下を指定): ```js //同一マスターシート(classA)で有効な承認図回覧(発行中/完了)の件数を取得 //(Status「300:回覧中」「310:再回覧中」「900:完了」のみを対象。「910:保留」「920:取消」は対象外) $p.ex.getKairanCount = function (classA) { let count = 0; if (!classA) return count; let view = { "ColumnFilterHash": { "ClassA": JSON.stringify([classA]), "Status": '["300","310","900"]' } }; $p.apiGet({ 'id': '492169', 'async': false, 'data': { 'ApiVersion': 1.1, 'ApiKey': apiKey, 'View': view }, 'done': function (data) { count = data.Response.TotalCount; }, 'fail': function (data) { console.log(data); } }); return count; } ``` - [ ] **Step 3: 呼び出し元が残っていないか確認** `hasPreviousApprovalReview`という文字列でファイル内を検索し、Task 2で書き換える1箇所(242行目)以外に呼び出しが無いことを確認する。 --- ### Task 2: `getMSSData` を新関数呼び出しに差し替え、ClassW仮セットを追加 **Files:** - Modify: `MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js:241-244` **Interfaces:** - Consumes: `$p.ex.getKairanCount(classA)`(Task 1で定義) - Produces: なし(画面項目`#Results_ClassZ`・`#Results_ClassW`へのセットのみ) - [ ] **Step 1: 対象箇所を確認する** `$p.ex.getMSSData`関数内、`if (data.Response.TotalCount == '1')`ブロックの先頭付近(241〜244行目): ```js //新規作成時、同一マスターシートで過去に承認図回覧が発行済みなら「回覧板名称」を変更 if ($p.action() == 'new' && $p.ex.hasPreviousApprovalReview(resultId)) { $p.set($('#Results_ClassZ'), '再承認図回覧'); } ``` - [ ] **Step 2: 置き換える** ```js //新規作成時、同一マスターシートの有効な承認図回覧件数を取得し、 //「回覧板名称」の変更(2件目以降なら再承認図回覧)と「回数」の仮セットを行う //(確定値はプロセス実行時(回覧発行/再回覧)に改めて再計算する) if ($p.action() == 'new') { let kairanCount = $p.ex.getKairanCount(resultId); if (kairanCount > 0) { $p.set($('#Results_ClassZ'), '再承認図回覧'); } $p.set($('#Results_ClassW'), String(kairanCount + 1).padStart(4, '0')); } ``` - [ ] **Step 3: 呼び出しタイミングを確認する** `getMSSData`は175〜198行目の`$p.on('change', 'ClassA', ...)`ハンドラから`$p.ex.clearMSSData()`→`$p.ex.getMSSData()`の順で呼ばれている(ClassA選択完了時に発火、要件通り)。コード変更は不要、確認のみ。 --- ### Task 3: `getUsedFileGuids` のStatusフィルタ変更 **Files:** - Modify: `MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js:392-397` **Interfaces:** - Consumes: なし - Produces: なし(既存の戻り値仕様は変更しない。フィルタ条件のみ変更) - [ ] **Step 1: 対象箇所を確認する** `$p.ex.getUsedFileGuids`関数内のview定義(392〜397行目): ```js let view = { "ColumnFilterHash": { "ClassA": JSON.stringify([classA]), "Status": '["300","310","900","910","920"]' } }; ``` - [ ] **Step 2: Statusフィルタのみ変更する** ```js let view = { "ColumnFilterHash": { "ClassA": JSON.stringify([classA]), "Status": '["300","310","900"]' } }; ``` --- ### Task 4: `processScript` の回覧発行・再回覧処理を確定回数の再計算に差し替え **Files:** - Modify: `MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js:642-647` (case '1') - Modify: `MSS回覧板システム/configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js:734-739` (case '10') **Interfaces:** - Consumes: `$p.ex.getKairanCount(classA)`(Task 1で定義) - Produces: なし(画面項目`#Results_ClassW`へのセットのみ) - [ ] **Step 1: case '1'(回覧発行)の対象箇所を確認する** ```js //自動採番(ClassV「[マスターシート]-[nnnn]」)の末尾4桁をClassW(回数)へ保存 let classV = $('#Results_ClassV').val(); if (classV) { let classVParts = classV.split('-'); $p.set($('#Results_ClassW'), classVParts[classVParts.length - 1]); } ``` - [ ] **Step 2: case '1'を置き換える** ```js //有効な承認図回覧件数を再カウントし、確定した回数をClassW(回数)へ保存 //(新規作成時のClassA選択時点から他の同一マスターシート回覧が先に発行された可能性があるため再計算する) let classA1 = $('#Results_ClassA').val(); let kairanCount1 = $p.ex.getKairanCount(classA1); $p.set($('#Results_ClassW'), String(kairanCount1 + 1).padStart(4, '0')); ``` - [ ] **Step 3: case '10'(再回覧)の対象箇所を確認する** ```js //自動採番(ClassV「[マスターシート]-[nnnn]」)の末尾4桁をClassW(回数)へ保存 let classV10 = $('#Results_ClassV').val(); if (classV10) { let classVParts10 = classV10.split('-'); $p.set($('#Results_ClassW'), classVParts10[classVParts10.length - 1]); } ``` - [ ] **Step 4: case '10'を置き換える** ```js //有効な承認図回覧件数を再カウントし、確定した回数をClassW(回数)へ保存 let classA10 = $('#Results_ClassA').val(); let kairanCount10 = $p.ex.getKairanCount(classA10); $p.set($('#Results_ClassW'), String(kairanCount10 + 1).padStart(4, '0')); ``` - [ ] **Step 5: `#Results_ClassV`参照が残っていないか確認** ファイル全体を`ClassV`で検索し、137〜148行目のコメントブロック(項目一覧メモ、`ClassW : エリア`という古い記述含む)以外に実コードでの参照が無いことを確認する。このコメントブロック自体は本改修と無関係の既存の古いメモのため触れない。 --- ### Task 5: staging反映 **Files:** - 参照: `.claude/js/build-desired-config.js` / `.claude/js/apply-desired-config-full.js`(共通ツール、変更なし) **Interfaces:** - Consumes: Task 1〜4で編集済みの`1_01_メインスクリプト.js` - Produces: staging環境SiteId 492169への反映結果(`modify/`フォルダへのプレビュー・送信結果保存) - [ ] **Step 1: 反映用JSONを作成する** ```bash node .claude/js/build-desired-config.js --project="MSS回覧板システム" --env=staging site-492169_承認図回覧 ``` Expected: `MSS回覧板システム/desired_config.json`が生成される。 - [ ] **Step 2: ドライラン確認** ```bash node .claude/js/apply-desired-config-full.js --project="MSS回覧板システム" --env=staging ``` Expected: Scripts差分に`01_メインスクリプト`の変更ありと表示。Columns/GridColumns/Permissions等は変更なしと表示。 - [ ] **Step 3: ユーザーに差分プレビューを提示し、`--execute`実行の許可を得る** このステップはコード変更ではなく、ユーザーへの確認。プレビュー内容(送信予定Body)を提示し、明示的な許可を得てから次へ進む。 - [ ] **Step 4: 実行** ```bash node .claude/js/apply-desired-config-full.js --project="MSS回覧板システム" --env=staging --execute ``` Expected: HTTP 200、`modify/`フォルダに送信結果JSON保存。 - [ ] **Step 5: 再取得して反映確認** ```bash node .claude/js/get-site-config.js --project="MSS回覧板システム" --env=staging ``` Expected: `configs/staging/site-492169_承認図回覧/scripts/1_01_メインスクリプト.js`がTask 1〜4の内容で更新されている。 - [ ] **Step 6: summary記録** `configs/staging/site-492169_承認図回覧/modify/`配下の最新フォルダに、変更点(Task1〜4の要約)・反映日時・反映結果をまとめた`summary_{timestamp}.md`を作成する。 --- ### Task 6: staging環境での動作確認(ブラウザ) **Files:** なし(手動確認のみ) **Interfaces:** - Consumes: Task 5で反映済みのstaging環境 - Produces: 動作確認結果の報告 - [x] **Step 1: 新規作成→仮回数セット確認** staging環境で承認図回覧を新規作成し、マスターシート(ClassA)を選択する。過去に同一マスターシートで発行済み承認図回覧(Status 300/310/900のいずれか)が無い場合はClassW=`0001`、ある場合は`0002`以降になること、また既存があれば「再承認図回覧」ラベルに変わることを確認する。 **確認結果(2026-08-31、Selenium自動操作)**: ClassA=384634(過去0件)→`ClassW=0001`/`ClassZ=承認図回覧`(未変更)。ClassA=339580(過去3件)→`ClassW=0004`/`ClassZ=再承認図回覧`。いずれもAPI実データと完全一致。 - [x] **Step 2: 回覧発行→確定回数確認** Step 1で作成したレコードで「回覧発行」プロセス(Status100→300)を実行し、ClassWが新規作成時の仮値のまま(または他レコードが割り込んでいれば再計算された値)で確定することを確認する。 **確認結果**: ClassA=464949でレコード504734を新規作成(NumA=17件、過去回覧0件)→保存→`#Process_1`実行(confirm()はwindow.confirmオーバーライドで自動承認)→Status100→300遷移、`ClassW=0001`で確定。実際に通知メール送信済み(ユーザー承認済み)。 - [x] **Step 3: 保留・取消レコードが回数に影響しないことを確認** 同一マスターシートで別レコードを新規作成→回覧発行→「回覧保留」または「回覧取消」プロセスを実行しStatus910/920にした上で、さらに別レコードを新規作成した際、保留・取消済みレコードがClassWのカウントに含まれない(件数が増えない)ことを確認する。 **確認結果**: 既存データからClassA=318755(取消920が1件、有効300が1件)のケースで新規作成→`ClassW=0002`(取消分は除外、有効1件のみ+1)、`ClassZ=再承認図回覧`。期待通り。 - [x] **Step 4: 差戻し→再回覧で回数が再計算されることを確認** 回覧中のレコードを「差戻し」(Status→110)した後、「再回覧」プロセス(Status110→310)を実行し、ClassWが再計算されることを確認する。 **確認結果**: 504734についてAPI直接更新でStatus→110にした後(差戻しプロセス自体はClassY:Own条件をSeleniumログインユーザーが満たさず実行不可のため、Status変更のみAPI代替)、`#Process_10`(再回覧)をクリックしStatus110→310遷移、`ClassW=0001`維持を確認。 **追加検証(getUsedFileGuidsの動作確認、ユーザー指示)**: 504734のDescriptionAから「承認図・詳細図」ファイル1件(Guid: 1E5913C612A24600B65544CEE24F1B86)の記載を意図的に除去(=未使用と誤判定させる細工)→同一マスターシート(464949)で2件目を新規作成→`ClassW=0002`/`ClassZ=再承認図回覧`、かつ`NumA=1`・除去したGuidが候補として再掲載されることを確認。使用済みファイルはDescriptionA記載を根拠に判定される仕組みが正しく機能していることを実証。 **後処理**: テストレコード504733・504734・DescriptionA改変状態はユーザー指示によりそのまま残置(削除・復元なし)。 --- ## Self-Review **Spec coverage:** - ClassV自動採番除外 → 本計画のスコープ外(staging側は既に処理済み、production反映は別フェーズ)と明記済み - ClassW算出方式を「既存レコード参照カウント方式」に変更 → Task 1, 2, 4でカバー - 新規作成時・300移行時の2回判定 → Task 2(新規作成時)・Task 4(プロセス実行時)でカバー - Status対象範囲(300,310,900のみ、910/920除外) → Task 1のフィルタで反映 - 再承認図判定への統合 → Task 1で`hasPreviousApprovalReview`を`getKairanCount`に一本化 - 再回覧(Process10)時も再計算対象に含める → Task 4でcase '10'も変更 - getUsedFileGuidsも910/920除外 → Task 3でカバー **Placeholder scan:** 該当なし。全Stepに実コードを記載済み。 **Type consistency:** `getKairanCount(classA)`は全呼び出し箇所(Task 2, Task 4のcase 1/case 10)で同じ引数1つ・Number返却として統一。変数名`kairanCount`/`kairanCount1`/`kairanCount10`は既存コードの命名規則(`classV`/`classV10`のようにcase番号をサフィックス)を踏襲し衝突を回避。