# 機能設計書 22-テスト結果表示

## 概要

本ドキュメントは、InvenTreeアプリにおけるテスト結果表示機能の設計を記載する。在庫アイテムに対するテスト結果を表示し、品質管理に必要なトレーサビリティを提供する機能である。

### 本機能の処理概要

**業務上の目的・背景**：製造業や品質管理において、製品や部品に対するテスト結果を記録・追跡することは、品質保証、法規制対応、顧客要求への適合において必須である。本機能により、各在庫アイテムのテストテンプレートに対する合否状態を確認し、新しいテスト結果を登録できる。

**機能の利用シーン**：在庫詳細画面からテスト結果を確認する際、または受入検査・出荷検査などの品質チェック時に利用される。テンプレートに基づいた体系的なテスト管理が可能。

**主要な処理内容**：
1. 在庫アイテムに関連するテストテンプレートをAPIから取得
2. 既存のテスト結果をAPIから取得
3. テンプレートと結果をマージして一覧表示
4. 各テストの合否状態をアイコンで視覚的に表示
5. 新しいテスト結果の追加フォームを提供

**関連システム・外部連携**：InvenTree REST API（`stock/test/`エンドポイント）と連携し、テスト結果データを取得・登録する。パーツのテストテンプレート定義とも連携。

**権限による制御**：`stock`ロールを持つユーザーが閲覧可能。テスト結果の追加にはcanCreate権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 在庫アイテム詳細画面 | 遷移元画面 | テスト結果項目押下時にテスト結果画面へ遷移 |

## 機能種別

CRUD操作（参照・登録）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stock_item | int | Yes | 在庫アイテムのID | 正の整数 |
| template | int | No | テストテンプレートID | 正の整数 |
| result | bool | No | テスト合否 | true/false |
| value | String | No | テスト結果値 | - |
| notes | String | No | 備考 | - |
| attachment | File | No | 添付ファイル | - |

### 入力データソース

在庫詳細画面から渡される`InvenTreeStockItem`オブジェクトから在庫アイテムIDとパーツIDを取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| testName | String | テスト名 |
| result | bool | 合否結果 |
| value | String | テスト結果値 |
| date | String | テスト実施日 |
| username | String | 実施者 |
| required | bool | 必須テストか否か |

### 出力先

画面（リストビュー形式）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ StockItemTestResultsWidgetが在庫アイテムを受け取る
2. データ取得（request）
   ├─ getTestTemplates()でテストテンプレート取得
   └─ getTestResults()で既存テスト結果取得
3. テンプレートと結果のマージ
   └─ getTestResults()メソッドで統合
4. 一覧表示（getTiles）
   ├─ パーツ情報カード表示
   ├─ テスト結果セクション見出し
   └─ 各テスト項目をListTileで表示
5. テスト結果追加（addTestResult）
   └─ フォームダイアログで新規結果登録
```

### フローチャート

```mermaid
flowchart TD
    A[在庫詳細画面から遷移] --> B[StockItemTestResultsWidget初期化]
    B --> C[request呼び出し]
    C --> D[getTestTemplates]
    C --> E[getTestResults]
    D --> F[テンプレートと結果のマージ]
    E --> F
    F --> G[getTiles呼び出し]
    G --> H{テスト結果あり?}
    H -->|Yes| I[各テストをListTileで表示]
    H -->|No| J[結果なしメッセージ表示]
    I --> K[ListTile押下?]
    K -->|Yes| L[addTestResult呼び出し]
    K -->|No| M[表示完了]
    L --> N[createFormでフォーム表示]
    N --> O[登録成功?]
    O -->|Yes| P[refresh呼び出し]
    O -->|No| M
    P --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-22-01 | テンプレートマッチング | テスト結果はテンプレートIDまたはキーでマッチング | テンプレートが定義されている場合 |
| BR-22-02 | 最新結果優先 | 同一キーのテスト結果は最新のものを表示 | 複数結果がある場合 |
| BR-22-03 | 必須テスト強調 | 必須テストは太字で表示 | template.required == true |
| BR-22-04 | 合否アイコン表示 | 合格=緑チェック、不合格=赤×、未実施=青? | 常時 |
| BR-22-05 | 追加権限チェック | テスト結果追加ボタンはcanCreate時のみ表示 | canCreate == true |

### 計算ロジック

テンプレートの`passFailStatus()`メソッドで、そのテンプレートに対する最新結果の合否を判定。

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| テンプレート取得 | part_test_template | SELECT | パーツのテストテンプレート取得 |
| 結果取得 | stock_test_result | SELECT | 在庫のテスト結果取得 |
| 結果登録 | stock_test_result | INSERT | 新規テスト結果登録 |

### テーブル別操作詳細

#### stock_test_result（APIエンドポイント: stock/test/）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | stock_item | WHERE stock_item = :stockItemId | 対象在庫のみ |
| INSERT | stock_item | :stockItemId | 必須 |
| INSERT | template | :templateId | モダンAPI時 |
| INSERT | result | :result | true/false |
| INSERT | value | :value | オプション |
| INSERT | attachment | :file | オプション |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | トークン無効 | 再ログインを促す |
| 403 | 権限エラー | stockロール未付与 | 権限不足メッセージ表示 |
| 400 | バリデーションエラー | 必須項目未入力 | フォームにエラー表示 |
| 500 | サーバーエラー | サーバー側障害 | リトライを促す |

### リトライ仕様

ネットワークエラー時はユーザーによるプルダウンリフレッシュで再取得可能。

## トランザクション仕様

テスト結果登録はAPI側で単一トランザクションとして処理される。

## パフォーマンス要件

- テンプレートと結果を並行して取得
- 画面表示時に全件取得（ページネーションなし）

## セキュリティ考慮事項

- トークンベース認証による保護
- stockロールを持つユーザーのみアクセス可能
- ファイルアップロードはサーバー側でバリデーション

## 備考

- APIバージョン169以降は「モダン」テスト結果APIを使用（template指定）
- 旧APIでは`test`フィールドでテスト名を直接指定
- 添付ファイルは`fileField: "attachment"`で指定

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | stock.dart | `lib/inventree/stock.dart` | InvenTreeStockItemTestResultクラス（16-77行目） |
| 1-2 | part.dart | `lib/inventree/part.dart` | InvenTreePartTestTemplateクラス |

**読解のコツ**: テスト結果モデルは`formFields()`でフォーム定義を持ち、APIバージョンに応じてフィールドを切り替える（47-51行目）。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stock_item_test_results.dart | `lib/widget/stock/stock_item_test_results.dart` | StockItemTestResultsWidgetの全体構造（16-258行目） |

**主要処理フロー**:
1. **16-24行目**: StatefulWidgetの定義
2. **37-53行目**: actionButtonsでテスト追加ボタンを構築
3. **56-59行目**: requestでテンプレートと結果を取得
4. **63-93行目**: addTestResultでフォームを表示

#### Step 3: データマージ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stock_item_test_results.dart | `lib/widget/stock/stock_item_test_results.dart` | getTestResultsメソッド（96-140行目） |

**主要処理フロー**:
- **97-99行目**: テンプレートと結果を変数に取得
- **103-105行目**: 各テンプレートをoutputsに追加
- **108-136行目**: 各結果をテンプレートにマッチングまたは追加

#### Step 4: 表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | stock_item_test_results.dart | `lib/widget/stock/stock_item_test_results.dart` | getTilesメソッド（143-257行目） |

**主要処理フロー**:
- **146-154行目**: パーツ情報カードを表示
- **183-214行目**: テンプレートまたは結果から表示データを抽出
- **216-222行目**: 合否状態に応じたアイコン選択
- **224-249行目**: ListTileの構築とタップハンドラ設定

### プログラム呼び出し階層図

```
StockItemTestResultsWidget
    │
    ├─ _StockItemTestResultDisplayState
    │      │
    │      ├─ request()
    │      │      ├─ item.getTestTemplates()
    │      │      │      └─ InvenTreePartTestTemplate().list()
    │      │      └─ item.getTestResults()
    │      │             └─ InvenTreeStockItemTestResult().list()
    │      │
    │      ├─ getTestResults()  [データマージ処理]
    │      │
    │      ├─ getTiles()
    │      │      └─ 各テストのListTile構築
    │      │
    │      ├─ actionButtons()
    │      │      └─ SpeedDialChild（追加ボタン）
    │      │
    │      └─ addTestResult()
    │             └─ InvenTreeStockItemTestResult().createForm()
```

### データフロー図

```
[入力]                       [処理]                         [出力]

InvenTreeStockItem ─────▶ StockItemTestResultsWidget
       │                          │
       ├─ partId ─────────▶ getTestTemplates() ───▶ testTemplates[]
       │                          │
       └─ pk ─────────────▶ getTestResults() ────▶ testResults[]
                                  │
                                  ▼
                          getTestResults() [マージ]
                                  │
                                  ▼
                       InvenTreeModel[] (混合リスト)
                                  │
                                  ▼
                            getTiles()
                                  │
                                  ▼
                            ListTile[]
                      (アイコン・テスト名・値・日付)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| stock_item_test_results.dart | `lib/widget/stock/stock_item_test_results.dart` | ソース | テスト結果表示ウィジェット |
| stock.dart | `lib/inventree/stock.dart` | ソース | テスト結果モデル定義 |
| part.dart | `lib/inventree/part.dart` | ソース | テストテンプレートモデル定義 |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | 更新可能な状態の基底クラス |
| api.dart | `lib/api.dart` | ソース | API通信処理 |
| api_form.dart | `lib/api_form.dart` | ソース | フォーム生成処理 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応 |
| app_colors.dart | `lib/app_colors.dart` | ソース | 色定義（COLOR_SUCCESS, COLOR_DANGER等） |
