# 機能設計書 38-会社一覧表示

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおける会社（Company）一覧表示機能の設計を定義する。会社一覧は、サプライヤー・顧客・製造元などの取引先を管理するための基盤となる機能である。

### 本機能の処理概要

この機能では、InvenTreeサーバーに登録された会社（サプライヤー、顧客、製造元）をページネーション対応の一覧形式で表示し、フィルタリング・検索・新規作成を行うことができる。

**業務上の目的・背景**：在庫管理・発注・受注を行うためには、取引先（サプライヤー、顧客、製造元）の情報を管理する必要がある。会社一覧を通じて、取引先の情報を素早く検索・参照でき、新規取引先の登録も可能である。サプライヤーは発注先、顧客は受注元、製造元はパーツの製造元として、それぞれ異なる役割を持つが、同一の会社が複数の役割を持つことも可能である。

**機能の利用シーン**：
- サプライヤー一覧を確認して発注先を選択したい場合
- 顧客一覧を確認して受注元を確認したい場合
- 新規取引先（会社）を登録したい場合
- 特定の会社を検索したい場合

**主要な処理内容**：
1. フィルタ条件（is_supplier, is_customer等）に基づいて会社リストを取得
2. 会社名、説明、サムネイルを含む一覧を表示
3. 検索機能による会社の絞り込み
4. 会社タップで詳細画面へ遷移
5. 作成権限がある場合は新規会社作成ボタンを表示

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

**権限による制御**：会社の作成権限（`company` 権限の`add`）がある場合のみ、新規作成ボタンが表示される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ホーム画面 | 遷移元画面 | サプライヤー/顧客タイル押下時に会社一覧画面へ遷移 |
| 3 | 検索画面 | 遷移元画面 | 会社検索結果押下時に会社一覧画面へ遷移 |
| 30 | 会社一覧画面 | 主機能 | 会社のページネーション付き一覧表示 |
| 31 | 会社詳細画面 | 遷移先画面 | 会社選択時に会社詳細画面へ遷移 |

## 機能種別

データ表示（CRUD操作のRead・Create）/ 一覧表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| title | String | Yes | 画面タイトル（"Suppliers", "Customers"等） | - |
| filters | Map<String, String> | Yes | フィルタ条件 | - |

### フィルタ条件例

| フィルタ名 | 値 | 説明 |
|-----------|-----|------|
| is_supplier | true | サプライヤーのみ表示 |
| is_customer | true | 顧客のみ表示 |
| is_manufacturer | true | 製造元のみ表示 |

### フィルタオプション（APIサポート時）

| フィルタ名 | ラベル | 説明 | 条件 |
|-----------|--------|------|------|
| active | Active | アクティブな会社のみ表示 | supportsCompanyActiveStatus |

### 入力データソース

- InvenTree REST API (`/api/company/`)
- ユーザー入力（検索キーワード、フィルタ設定）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| name | String | 会社名 |
| description | String | 会社の説明 |
| image | String | 会社画像URL |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. ウィジェット初期化
   └─ CompanyListWidgetがタイトルとフィルタを受け取る
2. 画面構築
   └─ PaginatedCompanyListウィジェットを本体として構築
3. ページデータ取得
   └─ InvenTreeCompany().listPaginated()でAPIリクエスト
4. 一覧表示
   └─ 各会社をListTileとして描画（サムネイル付き）
5. ユーザー操作
   └─ タップで詳細画面、新規作成ボタンでフォーム表示
```

### フローチャート

```mermaid
flowchart TD
    A[画面表示開始] --> B[タイトル・フィルタ受け取り]
    B --> C[PaginatedCompanyList構築]
    C --> D{作成権限確認}
    D -->|権限あり| E[新規作成ボタン表示]
    D -->|権限なし| F[ボタン非表示]
    E --> G[APIからデータ取得]
    F --> G
    G --> H{データあり?}
    H -->|Yes| I[ListTileとして一覧表示]
    H -->|No| J[結果なしメッセージ表示]
    I --> K{ユーザー操作}
    K -->|アイテムタップ| L[詳細画面へ遷移]
    K -->|新規作成| M[作成フォーム表示]
    K -->|フィルタ変更| N[フィルタ設定画面]
    K -->|検索入力| O[検索実行]
    K -->|スクロール| P[次ページ取得]
    L --> Q[終了]
    M --> Q
    N --> G
    O --> G
    P --> G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-038-01 | 作成ボタン表示制御 | 会社の作成権限がある場合のみ新規作成ボタンを表示 | checkPermission("company", "add") |
| BR-038-02 | フィルタ継承 | 新規作成時、現在のフィルタ条件を初期値として設定 | 常時 |
| BR-038-03 | アクティブフィルタ | APIがsupportsCompanyActiveStatusをサポートする場合のみactiveフィルタを表示 | API条件 |
| BR-038-04 | ページサイズ | 1ページあたり25件を取得 | 常時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | company_company | SELECT | フィルタ条件に基づく会社一覧取得 |
| 新規作成 | company_company | INSERT | 新規会社レコード作成 |

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

#### company_company

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, description, image, is_supplier, is_customer, is_manufacturer, active | フィルタ条件適用 | ページネーション適用 |
| INSERT | name, description, website, is_supplier, is_customer, is_manufacturer, currency, active | フォーム入力値 | 新規作成時 |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

- 一覧取得：読み取り専用、トランザクション管理不要
- 新規作成：API側でトランザクション管理

## パフォーマンス要件

- 1ページあたり25件のデータを取得
- 無限スクロールによる段階的データ読み込み
- 検索入力は500msのデバウンス処理

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

- APIアクセスには認証トークンが必要
- 会社の閲覧には適切な権限が必要（purchase_order, sales_order, return_order）
- 作成操作には会社の作成権限（company:add）が必要

## 備考

- 画面タイトルはコンストラクタで指定され、フィルタ条件に応じて変化する（"Suppliers", "Customers"等）
- 新規作成時、現在のフィルタ条件（is_supplier等）が初期値として渡される
- 同一の会社がサプライヤー・顧客・製造元の複数の役割を持つことが可能

---

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

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

### 推奨読解順序

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

会社のデータモデルを理解する。

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

**読解のコツ**: InvenTreeCompanyはInvenTreeModelを継承している。isSupplier, isCustomer, isManufacturerの各プロパティでロールを判定。rolesRequiredは複数のロール（purchase_order, sales_order, return_order）を必要とする。

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

一覧画面の構成を把握する。

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

**主要処理フロー**:
1. **17-27行目**: CompanyListWidgetクラス定義。タイトルとフィルタを受け取る
2. **35-49行目**: _addCompany()メソッド。新規作成フォーム表示
3. **51-68行目**: actionButtons()メソッド。権限確認と新規作成ボタン構築

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | company_list.dart | `lib/widget/company/company_list.dart` | PaginatedCompanyListクラス（76-135行目） |

**主要処理フロー**:
- **93-105行目**: filterOptions。APIサポート状況に応じたactiveフィルタ
- **107-120行目**: requestPage()メソッド。APIからページデータ取得
- **122-134行目**: buildItem()メソッド。ListTile構築

#### Step 4: フォームフィールドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | company.dart | `lib/inventree/company.dart` | formFields()（40-56行目） |

**主要処理フロー**:
- **41-54行目**: フォームフィールド定義（name, description, website, is_supplier, is_customer, is_manufacturer, currency, active）

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

```
CompanyListWidget
    │
    ├─ _CompanyListWidgetState
    │      ├─ getAppBarTitle() → widget.title
    │      ├─ actionButtons() → 新規作成ボタン構築
    │      │      └─ _addCompany() → フォーム表示
    │      │             └─ InvenTreeCompany().createForm()
    │      └─ getBody() → PaginatedCompanyList
    │
    └─ PaginatedCompanyList
           └─ _CompanyListState
                  ├─ filterOptions → activeフィルタ（APIサポート時）
                  ├─ requestPage()
                  │      └─ InvenTreeCompany().listPaginated()
                  └─ buildItem()
                         ├─ サムネイル表示
                         ├─ 会社名
                         ├─ 説明
                         └─ onTap → company.goToDetailPage()
```

### データフロー図

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

タイトル ───────────▶ CompanyListWidget ───▶ アプリバータイトル
フィルタ条件                 │
    │                       ▼
    │               PaginatedCompanyList
    │                       │
    │                       ├─ フィルタ設定（active）
    │                       │
    ▼                       ▼
検索キーワード ────▶ requestPage()
                            │
                            ▼
                    InvenTreeAPI
                    /api/company/
                    ?is_supplier=true等
                            │
                            ▼
                    InvenTreePageResponse
                            │
                            ▼
                    buildItem()
                            │
                            ├─ サムネイル
                            ├─ 会社名
                            └─ 説明
                            │
                            ▼
                    ListTile一覧表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| company_list.dart | `lib/widget/company/company_list.dart` | ソース | 会社一覧ウィジェット |
| company.dart | `lib/inventree/company.dart` | ソース | 会社データモデル |
| company_detail.dart | `lib/widget/company/company_detail.dart` | ソース | 会社詳細画面 |
| paginator.dart | `lib/widget/paginator.dart` | ソース | ページネーション共通処理 |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | リフレッシュ可能State基底クラス |
| api.dart | `lib/api.dart` | ソース | API通信・権限確認・サムネイル取得 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応文字列 |
