# 機能設計書 9-BOM表示

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおけるBOM（Bill of Materials：部品表）表示機能の設計を記載する。パーツを構成する部品一覧（BOM）と、パーツがどの製品に使用されているか（Used In）を表示する機能を提供する。

### 本機能の処理概要

アセンブリパーツを構成するサブパーツの一覧（BOM）と、コンポーネントパーツが使用されている親パーツの一覧（Used In）を表示する機能である。ページネーション、フィルタリング、ソート機能を備える。

**業務上の目的・背景**：製造業において、製品を構成する部品表（BOM）は生産管理の基礎データである。BOMを確認することで、製品の製造に必要な部品と数量を把握でき、在庫確認や発注計画に活用できる。また、特定の部品がどの製品に使用されているかを把握することで、部品変更の影響範囲を特定できる。

**機能の利用シーン**：製品のBOM確認、部品の使用先確認、製造前の部品在庫チェック、部品廃止時の影響調査などで利用される。

**主要な処理内容**：
1. BOM一覧の表示（アセンブリパーツの場合）
2. Used In一覧の表示（コンポーネントパーツの場合）
3. フィルタリング（アクティブ、アセンブリ、バーチャル）
4. ソート（数量、パーツ名）
5. サブパーツ詳細への遷移

**関連システム・外部連携**：InvenTree REST API（bom/エンドポイント）

**権限による制御**：partロールのview権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | 部品詳細画面 | 遷移元画面 | BOMタイルまたはUsed Inタイルタップ時にBOM画面へ遷移 |

## 機能種別

データ参照 / 一覧表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| part | InvenTreePart | Yes | 対象パーツ | null不可 |
| isParentComponent | bool | No | BOM表示（true）かUsed In表示（false）か | デフォルト: true |
| filters | Map<String, String> | No | APIフィルタパラメータ | - |

### 入力データソース

- パーツ詳細画面から渡されるパーツオブジェクト
- 表示モード（BOM / Used In）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| bomItems | List<InvenTreeBomItem> | BOMアイテム一覧 |
| subPart | InvenTreePart | サブパーツ情報（BOM表示時） |
| part | InvenTreePart | 親パーツ情報（Used In表示時） |
| quantity | double | 数量 |
| reference | String | リファレンス番号 |

### 出力先

- UI（BOMリスト画面）

## 処理フロー

### 処理シーケンス

```
1. BOM画面表示
   └─ パーツ情報ヘッダー表示

2. BOMリスト取得
   └─ フィルタ構築（part or uses）
   └─ API呼び出し（bom/エンドポイント）
   └─ ページネーション処理

3. リストアイテム表示
   └─ サブパーツ名/親パーツ名
   └─ リファレンス
   └─ 数量

4. ユーザーアクション
   └─ フィルタボタン → フィルタオプション表示
   └─ アイテムタップ → パーツ詳細画面遷移
   └─ スクロール → 次ページ読み込み
```

### フローチャート

```mermaid
flowchart TD
    A[BOM画面表示] --> B{isParentComponent?}
    B -->|true| C[BOMモード：part=pk]
    B -->|false| D[Used Inモード：uses=pk]
    C --> E[フィルタ構築]
    D --> E
    E --> F[bom/ API呼び出し]
    F --> G[ページネーション処理]
    G --> H[BOMリスト表示]
    H --> I{ユーザー操作}
    I -->|フィルタ| J[フィルタオプション表示/非表示]
    J --> K[フィルタ適用]
    K --> F
    I -->|アイテムタップ| L[パーツ詳細取得]
    L --> M[パーツ詳細画面遷移]
    I -->|スクロール| N[次ページ読み込み]
    N --> F
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | BOMフィルタ | part={pk}でBOM取得 | isParentComponent=true |
| BR-02 | Used Inフィルタ | uses={pk}でUsed In取得 | isParentComponent=false |
| BR-03 | デフォルトフィルタ | sub_part_detail=true, part_detail=true | 常時 |
| BR-04 | アクティブフィルタ | sub_part_activeのデフォルトはtrue | フィルタ時 |
| BR-05 | バーチャルフィルタ | sub_part_virtualのデフォルトはtrue | フィルタ時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | - | - | サーバーAPIからのみ取得（ローカルDB操作なし） |

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

ローカルデータベース操作なし。サーバーAPIからのデータ取得のみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------
| 401/403 | 認証/権限エラー | partロールなし | エラーメッセージ表示 |
| 404 | 未検出エラー | パーツが存在しない | 空リスト表示 |
| 500+ | サーバーエラー | サーバー内部エラー | エラーメッセージ表示 |

### リトライ仕様

- プルリフレッシュによる手動リトライ
- ページネーション自動リトライなし

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

- 読み取り専用（トランザクションなし）

## パフォーマンス要件

- ページサイズ: 25件
- 無限スクロールによるページネーション
- サムネイル画像はキャッシュ利用

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

- partロールのview権限が必要
- 認証トークンによるAPI認証

## 備考

- アセンブリパーツの場合はBOMタイルが表示される
- コンポーネントパーツの場合はUsed Inタイルが表示される
- フィルタオプション: アクティブ、アセンブリ、バーチャル
- ソートオプション: 数量、パーツ名

---

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

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

### 推奨読解順序

#### Step 1: データモデルを理解する

まず、BOMアイテムのデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | bom.dart | `lib/inventree/bom.dart` | InvenTreeBomItemクラス（7-63行目） |

**読解のコツ**:
- **17行目**: URL定義（"bom/"）
- **20-26行目**: `defaultFilters` - sub_part_detail、part_detailをtrueに設定
- **29行目**: `reference` - BOMアイテムのリファレンス番号
- **32行目**: `quantity` - 必要数量
- **35行目**: `partId` - 親パーツID
- **38-47行目**: `part` - 親パーツオブジェクト（part_detailから構築）
- **50-59行目**: `subPart` - サブパーツオブジェクト（sub_part_detailから構築）
- **62行目**: `subPartId` - サブパーツID

#### Step 2: BOM表示ウィジェットを理解する

BOM表示画面の全体構造を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bom_list.dart | `lib/widget/part/bom_list.dart` | BillOfMaterialsWidgetクラス（19-92行目） |

**主要処理フロー**:
- **22-24行目**: コンストラクタ - part、isParentComponentパラメータ
- **40-46行目**: `getAppBarTitle` - BOM/Used Inタイトル切り替え
- **49-58行目**: `appBarActions` - フィルタボタン
- **61-91行目**: `getBody` - ヘッダーとPaginatedBomList表示
- **64-68行目**: フィルタ構築（part or uses）
- **72-80行目**: パーツ情報ヘッダー

#### Step 3: ページネーションリストを理解する

ページネーション対応のBOMリストを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | bom_list.dart | `lib/widget/part/bom_list.dart` | PaginatedBomListクラス（97-190行目） |
| 3-2 | paginator.dart | `lib/widget/paginator.dart` | PaginatedSearchWidget基底クラス（21-29行目） |

**主要処理フロー**:
- **116行目**: `prefix` - "bom_"（設定保存用プレフィックス）
- **119-122行目**: `orderingOptions` - ソートオプション（quantity、sub_part）
- **125-142行目**: `filterOptions` - フィルタオプション（active、assembly、virtual）
- **145-157行目**: `requestPage` - API呼び出し（listPaginated）
- **160-189行目**: `buildItem` - ListTile構築
- **163-165行目**: サブパーツ/親パーツの切り替え
- **177-187行目**: パーツ詳細画面への遷移

#### Step 4: 呼び出し元を理解する

パーツ詳細画面からの遷移を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | part_detail.dart | `lib/widget/part/part_detail.dart` | BOMタイル（594-612行目） |
| 4-2 | part_detail.dart | `lib/widget/part/part_detail.dart` | Used Inタイル（628-647行目） |

**主要処理フロー**:
- **594行目**: `part.isAssembly`条件でBOMタイル表示
- **595行目**: `showBom && bomCount > 0`条件
- **605-606行目**: BillOfMaterialsWidget(part, isParentComponent: true)
- **628行目**: `part.isComponent`条件でUsed Inタイル表示
- **629行目**: `showBom && usedInCount > 0`条件
- **640-641行目**: BillOfMaterialsWidget(part, isParentComponent: false)

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

```
PartDetailWidget (part_detail.dart)
    │
    ├─ partTiles() [594-612行目: BOMタイル]
    │      └─ BillOfMaterialsWidget(part, isParentComponent: true)
    │
    └─ partTiles() [628-647行目: Used Inタイル]
           └─ BillOfMaterialsWidget(part, isParentComponent: false)

BillOfMaterialsWidget (bom_list.dart)
    │
    ├─ getAppBarTitle() [40-46行目]
    │      └─ L10().billOfMaterials / L10().usedIn
    │
    ├─ appBarActions() [49-58行目]
    │      └─ フィルタトグル
    │
    └─ getBody() [61-91行目]
           ├─ パーツ情報ヘッダー
           └─ PaginatedBomList(filters)

PaginatedBomList (bom_list.dart)
    │
    ├─ filterOptions [125-142行目]
    │      └─ active, assembly, virtual
    │
    ├─ orderingOptions [119-122行目]
    │      └─ quantity, sub_part
    │
    ├─ requestPage() [145-157行目]
    │      └─ InvenTreeBomItem().listPaginated()
    │             └─ api.get("bom/", params)
    │
    └─ buildItem() [160-189行目]
           ├─ ListTile構築
           └─ onTap: part.goToDetailPage()
```

### データフロー図

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

InvenTreePart ───▶ BillOfMaterialsWidget ───▶ UI表示
    │                     │                       │
    ├─ pk                 ├─ isParentComponent    ├─ タイトル
    ├─ fullname           │    true: part=pk      │    BOM / Used In
    └─ thumbnail          │    false: uses=pk     │
                          │                       ├─ ヘッダー
                          ▼                       │    パーツ情報
                   PaginatedBomList               │
                          │                       └─ リスト
                          ├─ filterOptions            ├─ サブパーツ名
                          ├─ orderingOptions          ├─ リファレンス
                          └─ requestPage()            └─ 数量
                                 │
                                 ▼
                   InvenTreeBomItem.listPaginated()
                                 │
                                 ▼
                   bom/ API (GET)
                                 │
                                 ▼
                   List<InvenTreeBomItem>
                          │
                          ├─ subPart (sub_part_detail)
                          ├─ part (part_detail)
                          ├─ quantity
                          └─ reference
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bom_list.dart | `lib/widget/part/bom_list.dart` | ソース | BOM表示画面ウィジェット |
| bom.dart | `lib/inventree/bom.dart` | ソース | InvenTreeBomItemモデル |
| part_detail.dart | `lib/widget/part/part_detail.dart` | ソース | BOM/Used Inタイル（遷移元） |
| paginator.dart | `lib/widget/paginator.dart` | ソース | PaginatedSearchWidget基底クラス |
| part.dart | `lib/inventree/part.dart` | ソース | InvenTreePartモデル |
| model.dart | `lib/inventree/model.dart` | ソース | listPaginatedメソッド |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | RefreshableState基底クラス |
| progress.dart | `lib/widget/progress.dart` | ソース | ローディングオーバーレイ |
