# 機能設計書 40-サプライヤーパーツ詳細表示

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおけるサプライヤーパーツ詳細表示機能の設計を定義する。サプライヤーパーツは、特定のサプライヤーが供給する部品情報を管理するためのエンティティである。

### 本機能の処理概要

この機能では、サプライヤーパーツの詳細情報（内部パーツ参照、サプライヤー情報、SKU、製造元情報、梱包情報など）を表示し、編集・リンク操作を行うことができる。

**業務上の目的・背景**：サプライヤーパーツは、在庫管理と発注業務において重要な役割を果たす。同一の内部パーツに対して複数のサプライヤーから調達可能な場合、それぞれのサプライヤーごとの品番（SKU）、価格、梱包単位などの情報を管理する必要がある。サプライヤーパーツ詳細画面では、これらの情報を一元的に確認・編集できる。

**機能の利用シーン**：
- 発注時にサプライヤーごとの品番（SKU）を確認したい場合
- サプライヤーパーツに紐づく在庫を確認したい場合
- 製造元情報を確認したい場合
- サプライヤーパーツの梱包情報を確認したい場合
- サプライヤーパーツの情報を編集したい場合

**主要な処理内容**：
1. サプライヤーパーツデータの取得・表示
2. 内部パーツへのナビゲーション
3. サプライヤー会社へのナビゲーション
4. 製造元・製造元パーツへのナビゲーション
5. 在庫一覧へのナビゲーション
6. パラメータ・添付ファイルの表示
7. サプライヤーパーツ情報の編集

**関連システム・外部連携**：InvenTree REST API (`/api/company/part/`)

**権限による制御**：サプライヤーパーツの編集権限がある場合のみ、編集ボタンとカスタムバーコード設定が表示される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | パーツ詳細画面 | 遷移元/遷移先画面 | サプライヤーパーツ一覧からの遷移/内部パーツへの遷移 |
| 31 | 会社詳細画面 | 遷移先画面 | サプライヤー会社タップ時に会社詳細画面へ遷移 |
| 32 | サプライヤーパーツ詳細画面 | 主機能 | サプライヤーパーツの詳細表示 |
| 33 | 製造元パーツ詳細画面 | 遷移先画面 | 製造元パーツタップ時に製造元パーツ詳細画面へ遷移 |
| 15 | 在庫一覧画面 | 遷移先画面 | 在庫数タップ時に在庫一覧画面へ遷移 |

## 機能種別

データ表示（CRUD操作のRead・Update）/ 詳細表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| supplierPart | InvenTreeSupplierPart | Yes | 表示対象のサプライヤーパーツオブジェクト | pk > 0 |

### 入力データソース

- InvenTree REST API (`/api/company/part/{pk}/`)
- パラメータAPI (`/api/parameters/`)
- 添付ファイルAPI (`/api/attachment/`)

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| partName | String | 内部パーツ名 |
| active | bool | アクティブ状態 |
| inStock | double | 在庫数量 |
| supplierName | String | サプライヤー名 |
| SKU | String | サプライヤー品番 |
| manufacturerName | String | 製造元名（存在する場合） |
| MPN | String | 製造元品番（存在する場合） |
| packaging | String | 梱包情報 |
| pack_quantity | String | 梱包数量 |
| link | String | 外部リンク |
| note | String | メモ |
| parameterCount | int | パラメータ数 |
| attachmentCount | int | 添付ファイル数 |

### 出力先

画面表示（ListTileのリスト形式）

## 処理フロー

### 処理シーケンス

```
1. ウィジェット初期化
   └─ SupplierPartDetailWidgetがサプライヤーパーツオブジェクトを受け取る
2. データリロード
   └─ request()メソッドでサプライヤーパーツをリロード
3. 関連データカウント
   ├─ パラメータ数の非同期カウント
   └─ 添付ファイル数の非同期カウント
4. 詳細タイル構築
   └─ getTiles()メソッドで各情報をListTileとして描画
5. ユーザー操作
   ├─ 内部パーツタップ → パーツ詳細画面へ遷移
   ├─ サプライヤータップ → 会社詳細画面へ遷移
   ├─ 製造元タップ → 会社詳細画面へ遷移
   ├─ 製造元パーツタップ → 製造元パーツ詳細画面へ遷移
   ├─ 在庫タップ → 在庫一覧画面へ遷移
   ├─ リンクタップ → 外部ブラウザで開く
   └─ 編集ボタン → 編集フォーム表示
```

### フローチャート

```mermaid
flowchart TD
    A[画面表示開始] --> B[サプライヤーパーツ受け取り]
    B --> C[request実行]
    C --> D{reload成功?}
    D -->|No| E[画面をpop]
    D -->|Yes| F[パラメータ数カウント]
    F --> G[添付ファイル数カウント]
    G --> H[getTiles実行]
    H --> I[内部パーツタイル]
    I --> J{active?}
    J -->|No| K[非アクティブ警告表示]
    J -->|Yes| L[在庫タイル]
    K --> L
    L --> M[サプライヤータイル]
    M --> N[SKUタイル]
    N --> O{製造元パーツあり?}
    O -->|Yes| P[製造元タイル・MPNタイル]
    O -->|No| Q[梱包タイル]
    P --> Q
    Q --> R{リンクあり?}
    R -->|Yes| S[リンクタイル]
    R -->|No| T[ノートタイル]
    S --> T
    T --> U[パラメータタイル]
    U --> V[添付ファイルタイル]
    V --> W{ユーザー操作}
    W -->|内部パーツタップ| X[パーツ詳細画面]
    W -->|サプライヤータップ| Y[会社詳細画面]
    W -->|在庫タップ| Z[在庫一覧画面]
    W -->|編集ボタン| AA[編集フォーム]
    W -->|リンクタップ| AB[外部ブラウザ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-040-01 | 編集ボタン表示制御 | 編集権限がある場合のみアプリバーに編集ボタンを表示 | canEdit |
| BR-040-02 | バーコードボタン表示制御 | 編集権限がある場合のみカスタムバーコード設定ボタンを表示 | canEdit |
| BR-040-03 | 非アクティブ警告 | アクティブでないサプライヤーパーツには警告タイルを表示 | !active |
| BR-040-04 | 製造元表示条件 | 製造元パーツIDが0より大きい場合のみ製造元情報を表示 | manufacturerPartId > 0 |
| BR-040-05 | 梱包表示条件 | packagingまたはpack_quantityが空でない場合のみ梱包タイルを表示 | packaging.isNotEmpty or pack_quantity.isNotEmpty |
| BR-040-06 | リンク表示条件 | リンクが設定されている場合のみリンクタイルを表示 | hasLink |
| BR-040-07 | ノート表示条件 | ノートが空でない場合のみノートタイルを表示 | note.isNotEmpty |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 詳細取得 | company_supplierpart | SELECT | サプライヤーパーツ詳細データ取得 |
| 編集 | company_supplierpart | UPDATE | サプライヤーパーツ情報更新 |
| パラメータ取得 | template_parameters | SELECT | パラメータ数カウント |
| 添付ファイル取得 | attachment | SELECT | 添付ファイル数カウント |

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

#### company_supplierpart

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | supplier, part, SKU, link, note, packaging, pack_quantity, active, manufacturer_part | pk指定 | 詳細取得 |
| UPDATE | supplier, SKU, link, note, packaging, pack_quantity, active | フォーム入力値 | 編集時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | APIトークンが無効 | ログイン画面へ遷移 |
| 403 | 権限エラー | 閲覧権限がない | エラーメッセージ表示 |
| 404 | データなし | サプライヤーパーツが存在しない | 画面をpop |
| 500 | サーバーエラー | サーバー側の問題 | リトライを促すメッセージ表示 |

### リトライ仕様

プルダウンによるリフレッシュ操作で再取得可能

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

- 詳細取得：読み取り専用、トランザクション管理不要
- 編集：API側でトランザクション管理

## パフォーマンス要件

- パラメータ数・添付ファイル数は非同期で取得し、画面表示をブロックしない
- 関連データ（パーツ、会社、製造元パーツ）取得時はローディングオーバーレイを表示

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

- APIアクセスには認証トークンが必要
- サプライヤーパーツの閲覧にはpart, purchase_order権限が必要
- 編集操作には対応する編集権限が必要

## 備考

- 外部リンク（link）はopenLink()メソッドで外部ブラウザに遷移
- pack_quantityはAPIバージョンによりpack_sizeからpack_quantityに変更（APIバージョン117以降）
- 製造元パーツ詳細画面はManufacturerPartDetailWidgetで別途実装

---

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

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

### 推奨読解順序

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

サプライヤーパーツのデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | company.dart | `lib/inventree/company.dart` | InvenTreeSupplierPartクラスの構造（117-232行目） |

**読解のコツ**: InvenTreeSupplierPartはInvenTreeModelを継承している。rolesRequiredは["part", "purchase_order"]。defaultFilters()でmanufacturer_detail, supplier_detail, part_detailをtrueに設定し、関連データを一括取得。APIバージョンによりpack_sizeとpack_quantityの使い分けがある。

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

詳細画面の構成を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | SupplierPartDetailWidgetの構造全体 |

**主要処理フロー**:
1. **28-36行目**: SupplierPartDetailWidgetクラス定義。InvenTreeSupplierPartを受け取る
2. **38-135行目**: _SupplierPartDisplayStateクラス。RefreshableStateを継承
3. **46行目**: getAppBarTitle()でタイトル「Supplier Part」を返す

#### Step 3: データ取得処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | request()メソッド（100-135行目） |

**主要処理フロー**:
- **102-108行目**: reload()でサプライヤーパーツをリロード。失敗時はpop()
- **110-121行目**: パラメータ数の非同期カウント
- **123-134行目**: 添付ファイル数の非同期カウント

#### Step 4: 表示タイル構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | getTiles()メソッド（140-349行目） |

**主要処理フロー**:
- **150-166行目**: 内部パーツタイル（パーツ詳細画面へ遷移）
- **168-179行目**: 非アクティブ警告タイル
- **181-201行目**: 在庫タイル（在庫一覧画面へ遷移）
- **203-222行目**: サプライヤータイル（会社詳細画面へ遷移）
- **224-231行目**: SKUタイル
- **233-280行目**: 製造元・MPNタイル（条件付き表示）
- **282-297行目**: 梱包タイル（条件付き表示）
- **299-311行目**: リンクタイル（条件付き表示）
- **313-321行目**: ノートタイル（条件付き表示）
- **323-346行目**: パラメータ・添付ファイルタイル

#### Step 5: 編集機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | editSupplierPart()メソッド（51-60行目） |
| 5-2 | supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | appBarActions()メソッド（81-98行目） |
| 5-3 | supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | barcodeButtons()メソッド（62-79行目） |

**主要処理フロー**:
- **51-60行目**: editForm()でサプライヤーパーツ編集フォームを表示
- **85-94行目**: canEditの場合のみ編集ボタンを表示
- **66-76行目**: canEditの場合のみカスタムバーコードアクションを表示

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

```
SupplierPartDetailWidget
    │
    └─ _SupplierPartDisplayState (RefreshableState継承)
           ├─ getAppBarTitle() → "Supplier Part"
           ├─ appBarActions() → 編集ボタン（canEdit時）
           │      └─ editSupplierPart()
           │             └─ supplierPart.editForm()
           ├─ barcodeButtons() → カスタムバーコード（canEdit時）
           │      └─ customBarcodeAction()
           ├─ request()
           │      ├─ supplierPart.reload()
           │      ├─ InvenTreeParameter().countParameters()
           │      └─ InvenTreeAttachment().countAttachments()
           └─ getTiles()
                  ├─ 内部パーツタイル
                  │      └─ InvenTreePart().get() → goToDetailPage()
                  ├─ 非アクティブ警告タイル（!active時）
                  ├─ 在庫タイル
                  │      └─ StockItemList({supplier_part: pk})
                  ├─ サプライヤータイル
                  │      └─ InvenTreeCompany().get() → goToDetailPage()
                  ├─ SKUタイル
                  ├─ 製造元タイル（manufacturerPartId > 0時）
                  │      └─ InvenTreeCompany().get() → goToDetailPage()
                  ├─ MPNタイル（manufacturerPartId > 0時）
                  │      └─ InvenTreeManufacturerPart().get()
                  │             └─ ManufacturerPartDetailWidget
                  ├─ 梱包タイル（packaging/pack_quantity存在時）
                  ├─ リンクタイル（hasLink時）
                  │      └─ supplierPart.openLink()
                  ├─ ノートタイル（note存在時）
                  ├─ ShowParametersItem()
                  └─ ShowAttachmentsItem()
```

### データフロー図

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

InvenTreeSupplierPart ──▶ SupplierPartDetailWidget ──▶ アプリバータイトル
        │                        │                      編集ボタン
        │                        ▼
        │                   request()
        │                        │
        │                        ├─ supplierPart.reload()
        │                        │        │
        │                        │        ▼
        │                        │   InvenTreeAPI
        │                        │   /api/company/part/{pk}/
        │                        │
        │                        ├─ countParameters() ──▶ parameterCount
        │                        │
        │                        └─ countAttachments() ──▶ attachmentCount
        │
        │                        ▼
        │                   getTiles()
        │                        │
        └────────────────────────┤
                                 ├─ partName ──────────▶ 内部パーツタイル
                                 ├─ active ────────────▶ 非アクティブ警告
                                 ├─ inStock ───────────▶ 在庫タイル
                                 ├─ supplierName ──────▶ サプライヤータイル
                                 ├─ SKU ───────────────▶ SKUタイル
                                 ├─ manufacturerName ──▶ 製造元タイル
                                 ├─ MPN ───────────────▶ MPNタイル
                                 ├─ packaging ─────────▶ 梱包タイル
                                 ├─ pack_quantity
                                 ├─ link ──────────────▶ リンクタイル
                                 ├─ note ──────────────▶ ノートタイル
                                 ├─ parameterCount ────▶ パラメータタイル
                                 └─ attachmentCount ───▶ 添付ファイルタイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| supplier_part_detail.dart | `lib/widget/company/supplier_part_detail.dart` | ソース | サプライヤーパーツ詳細ウィジェット |
| company.dart | `lib/inventree/company.dart` | ソース | サプライヤーパーツデータモデル |
| manufacturer_part_detail.dart | `lib/widget/company/manufacturer_part_detail.dart` | ソース | 製造元パーツ詳細画面 |
| company_detail.dart | `lib/widget/company/company_detail.dart` | ソース | 会社詳細画面 |
| stock_list.dart | `lib/widget/stock/stock_list.dart` | ソース | 在庫一覧画面 |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | リフレッシュ可能State基底クラス |
| parameter_widget.dart | `lib/widget/parameter_widget.dart` | ソース | パラメータ表示ウィジェット |
| attachment_widget.dart | `lib/widget/attachment_widget.dart` | ソース | 添付ファイル表示ウィジェット |
| barcode.dart | `lib/barcode/barcode.dart` | ソース | バーコード関連機能 |
| api.dart | `lib/api.dart` | ソース | API通信・権限確認 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応文字列 |
