ken_nogi/XVBA/新版着工要因閲覧シート/docs/superpowers/specs/2026-09-11-export-get-switch-design.md
Kenichiro NOGI ee1448504c docs: Filter/Sorter対応・API仕様訂正をspecに反映
PleasanterのGet API仕様(PageSizeはクライアント指定不可、Response.Dataが直接配列、ClassHash等のネスト構造)を公式マニュアルで確認し訂正。
併せてFilter/Sorter条件をシート上の表で指定できる機能をExport/Get共通で追加する設計に更新。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 11:14:24 +09:00

8.6 KiB
Raw Blame History

Export/Get方式切替 設計書

背景・目的

現状 Module1.bas はPleasanterの Export API(CSV全件取得)でデータを取得し、CSVパース後にテーブルへ書き込んでいる。これに加えて Get API(api-record-get-multi)でデータを取得する方式を追加し、基本情報シートのセルで方式を切り替えて実行できるようにする。両方式の処理時間を比較できるよう、開始・終了時刻と経過秒数をシートに記録する。

対象件数は200件以下を想定し、ページング処理は考慮しない。

セル配置(基本情報シート)

セル 内容
D3 ステータスメッセージ(「取込処理中...」「取込処理完了」)
D4 処理開始時刻(Now
D5 処理終了時刻(Now
D6 経過秒数((D5 - D4) * 86400 の数値)
D7 取得方式("Export" または "Get"。未入力・それ以外の値は "Export" 扱い)

Filter・Sorter条件基本情報シート、Export/Get共通

Pleasanter APIの ColumnFilterHash / ColumnSorterHash に渡す条件を、基本情報シート上の表で指定できるようにする。Export方式・Get方式の両方で同じ条件を使う。

セル配置

見出し データ行
Filter表 F2:G2列名 / 値) F3以降列名が空白の行で終了
Sorter表 H2:I2列名 / 昇降順) H3以降ascまたはdesc。列名が空白の行で終了)
  • Filter表・Sorter表とも、データ行が1件も無ければ該当するHashはAPIリクエストに含めない
  • 両方とも0件の場合は View パラメータ自体をリクエストボディに含めない

SetupFilterSorterTables()新規・セットアップ用Sub

基本情報シートのF2:G2、H2:I2を見出しとするExcelテーブルListObjectを新規作成する。新版着工要因閲覧シートv0.1.xlsm 上で手動実行することを想定したセットアップ専用処理(run() からは呼ばない)。既にテーブルが存在する場合は何もしない。

BuildViewFromSheet() As Object(新規・共通関数)

基本情報シートのFilter表・Sorter表を読み取り、APIリクエストの View に渡す Dictionary を組み立てて返す。Filter表・Sorter表がともに0件の場合は Nothing を返す。

  • Filter表の各行から colFilter.Add 列名, 値ColumnFilterHash 用Dictionaryを作る1件以上ある場合のみ
  • Sorter表の各行から colSorter.Add 列名, 昇降順ColumnSorterHash 用Dictionaryを作る1件以上ある場合のみ
  • どちらか一方でもあれば View Dictionaryに ColumnFilterHash / ColumnSorterHash をそれぞれ追加(無い方は追加しない)
  • exportCSVDatagetRecordsData の両方から呼び出し、viewObjNothing でなければ apiBody.Add "View", viewObj する

全体フロー(Sub run()

Sub run()
    Call init   ' defaultSh, tableId, apiKey, baseURL, fetchMethod(D7の値) をセット

    defaultSh.Range("D4").Value = Now
    defaultSh.Range("D3").Value = "取込処理中..."
    Application.ScreenUpdating = False
    Application.Calculation = xlManual

    Select Case fetchMethod
        Case "Get"
            Call runGetFlow
        Case Else
            Call runExportFlow
    End Select

    Application.Calculation = xlAutomatic
    Application.ScreenUpdating = True
    defaultSh.Range("D5").Value = Now
    defaultSh.Range("D6").Value = (defaultSh.Range("D5").Value - defaultSh.Range("D4").Value) * 86400
    defaultSh.Range("D3").Value = "取込処理完了"
End Sub
  • init()fetchMethod = defaultSh.Range("D7").Value の読み込みを追加する。
  • runExportFlow は既存の exportCSVDataexportCSVDataToSheet 呼び出しをそのまま移設したもの(ロジック無変更)。
  • runGetFlow は新規追加の getRecordsDatagetRecordsDataToSheet を呼ぶ。

Export方式Filter/Sorter対応のため一部変更

exportCSVDataToSheet / ParseCsv / CollectionToArray は変更しない。

exportCSVData のみ、既存のコメントアウトされた colFilter / view 部分を BuildViewFromSheet() 呼び出しに置き換える。

Dim viewObj As Object
Set viewObj = BuildViewFromSheet()
If Not viewObj Is Nothing Then
    apiBody.Add "View", viewObj
End If

(旧来の yearFilter を使ったコメントアウトコードは削除する)

Get方式新規追加

getRecordsData(tableId As String) As Collection

Pleasanterの api-record-get-multi を呼び出し、レコード配列Collection of Dictionaryを返す。

  • エンドポイント: POST {baseURL}/pleasanter/api/items/{tableId}/get
  • リクエストボディ: ApiVersion, ApiKey
  • 取得件数は指定しない。1回のリクエストでの取得上限はサーバー側既定値Api.jsonPageSize、既定200件であり、クライアント側から PageSize を指定するパラメータは存在しない。200件以下想定のため既定動作のまま1回のリクエストで取得しきるOffset も指定不要)
  • レスポンス: res("Response")("Data") を返すレコードDictionaryの配列。Results という入れ子は存在しない)
  • 既存の callRestApi をそのまま利用する
  • Filter/Sorter条件は BuildViewFromSheet() を呼び出し、viewObjNothing でなければ apiBody.Add "View", viewObj するExport方式と同じ共通関数を利用

レコードのフラット化(FlattenRecord(record As Dictionary) As Dictionary

Pleasanterのget APIレスポンスは、ClassAClassZ などの項目が ClassHash(同様に NumHash, DateHash, DescriptionHash, CheckHash など)という入れ子のDictionaryの中に格納されている。トップレベルキーをそのままヘッダにすると、これらHash系フィールドが展開されずネストしたDictionaryのまま1セルに入ってしまう。

そのため getRecordsDataToSheet に渡す前に、各レコードをフラット化する処理を挟む。

  • レコードDictionaryの各キー・値を走査する
  • 値が Dictionary である場合(ClassHash など *Hash 系フィールド)は、そのキー自体は使わず、中身のキー・値をそのままフラット化後のDictionaryにマージする(例: ClassHash("ClassA") → フラット化後の ClassA キー)
  • 値が Dictionary でない単純値(Title, Body, Status, ResultId など)はそのままキー・値を引き継ぐ
  • 全レコードに対して同じ処理を行う

getRecordsDataToSheet(records As Collection, targetSheet As String)

exportCSVDataToSheet とは完全に独立した新規関数として実装する(既存ロジックへの影響を避けるため共通化しない)。

  • records.count = 0 の場合はメッセージ表示して終了
  • 各レコードを FlattenRecord でフラット化する
  • ヘッダは フラット化後の1件目レコードのキー一覧をそのまま使用Title, Body, ClassA, DateA などPleasanterの内部キー名。日本語ラベルへの変換は行わない
  • 各レコードフラット化後の値をヘッダ順に2次元配列へ格納
  • シート・テーブルListObjectの取得新規作成、ヘッダ設定、DataBodyRange のクリアと書き込みは exportCSVDataToSheet と同様の手順を独自に実装する
  • テーブル名・出力先シートは targetSheettableIdを共用し、Export方式実行時に作られた既存テーブルを上書きする方式を切り替えるたびにヘッダ列構成が変わる点は許容する

変更対象・追加対象まとめ

  • 変更: init()fetchMethod 読み込み追加), Sub run()(分岐フローに書き換え), exportCSVDataView 組み立てを BuildViewFromSheet() 呼び出しに置き換え)
  • 追加: runExportFlow, runGetFlow, getRecordsData, getRecordsDataToSheet, FlattenRecord, BuildViewFromSheet, SetupFilterSorterTables
  • 無改造: exportCSVDataToSheet, ParseCsv, CollectionToArray, callRestApi

非対象・考慮しないこと

  • 200件を超えるページング処理
  • Get方式でのヘッダの日本語ラベル化・Export方式との列対応付け
  • Get方式・Export方式のテーブルを別シートに分離すること同一テーブルを共用する