# 機能設計書 39-会社詳細表示

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおける会社（Company）詳細表示機能の設計を定義する。会社詳細画面は、個々の取引先（サプライヤー、顧客、製造元）に関する包括的な情報を表示し、関連する発注・受注・サプライヤーパーツへのアクセスを提供する中心的な画面である。

### 本機能の処理概要

この機能では、個々の会社の詳細情報を表示し、会社の編集、関連する発注・受注の作成、サプライヤーパーツ一覧へのアクセスなどの操作を提供する。

**業務上の目的・背景**：取引先の詳細情報を一元的に管理することは、効率的なサプライチェーン管理に不可欠である。会社詳細画面では、連絡先情報（ウェブサイト、メール、電話）、ロール（サプライヤー、顧客、製造元）に基づく関連注文、サプライヤーパーツなどを確認できる。また、会社がアクティブかどうかの状態も表示され、非アクティブな会社には視覚的な警告が表示される。

**機能の利用シーン**：
- 取引先の連絡先情報を確認したい場合
- サプライヤーに対して発注を作成したい場合
- 顧客に対して受注を作成したい場合
- サプライヤーが提供するパーツ一覧を確認したい場合
- 会社情報を編集したい場合
- 会社の添付ファイルを確認・追加したい場合

**主要な処理内容**：
1. 会社の詳細情報をAPIから取得・表示
2. 連絡先情報（ウェブサイト、メール、電話、リンク）の表示と外部アプリ連携
3. ロールに応じた関連情報表示（サプライヤーパーツ、発注、受注）
4. 発注・受注の作成ショートカット
5. パラメータ・添付ファイルの表示

**関連システム・外部連携**：
- InvenTree REST API (`/api/company/`)
- 外部アプリ連携（ブラウザ、メール、電話）

**権限による制御**：
- 会社の編集権限がある場合のみ、編集ボタンが表示される
- 発注作成には発注の作成権限が必要
- 受注作成には受注の作成権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 30 | 会社一覧画面 | 遷移元画面 | 会社選択時に会社詳細画面へ遷移 |
| 31 | 会社詳細画面 | 主機能 | 会社の詳細情報表示と各種操作 |
| 26 | 購入注文一覧画面 | 遷移先画面 | 発注項目押下時に発注一覧画面へ遷移（サプライヤーフィルタ） |
| 28 | 販売注文一覧画面 | 遷移先画面 | 受注項目押下時に受注一覧画面へ遷移（顧客フィルタ） |

## 機能種別

データ表示（CRUD操作のRead・Update）/ 詳細表示 / 新規作成（関連注文）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| company | InvenTreeCompany | Yes | 対象の会社オブジェクト | PKが1以上であること |

### 入力データソース

- 会社一覧画面から渡される会社オブジェクト
- InvenTree REST API（詳細情報のリロード）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| name | String | 会社名 |
| description | String | 会社の説明 |
| image | String | 会社画像URL |
| website | String | ウェブサイトURL |
| email | String | メールアドレス |
| phone | String | 電話番号 |
| link | String | 外部リンク |
| isSupplier | bool | サプライヤーフラグ |
| isCustomer | bool | 顧客フラグ |
| isManufacturer | bool | 製造元フラグ |
| active | bool | アクティブフラグ |
| notes | String | ノート |

### 出力先

画面表示（タイルリスト形式）

## 処理フロー

### 処理シーケンス

```
1. ウィジェット初期化
   └─ CompanyDetailWidgetが会社オブジェクトを受け取る
2. データ読み込み
   ├─ 会社データのリロード
   ├─ 未処理発注数のカウント（サプライヤーの場合）
   ├─ 未処理受注数のカウント（顧客の場合）
   ├─ サプライヤーパーツ数のカウント
   ├─ パラメータ数のカウント
   └─ 添付ファイル数のカウント
3. 画面構築
   └─ 各情報タイルを構築
4. ユーザー操作
   ├─ 編集ボタン → 編集フォーム
   ├─ ウェブサイト → 外部ブラウザ
   ├─ メール → メールアプリ
   ├─ 電話 → 電話アプリ
   ├─ サプライヤーパーツ → サプライヤーパーツ一覧
   ├─ 発注 → 発注一覧（サプライヤーフィルタ）
   ├─ 受注 → 受注一覧（顧客フィルタ）
   ├─ 発注作成 → 発注作成フォーム
   └─ 受注作成 → 受注作成フォーム
```

### フローチャート

```mermaid
flowchart TD
    A[画面表示開始] --> B[会社オブジェクト受け取り]
    B --> C[company.reload]
    C --> D{reload成功?}
    D -->|No| E[前画面へ戻る]
    D -->|Yes| F[関連データカウント取得]
    F --> G[画面構築]
    G --> H{ロール確認}
    H -->|isSupplier| I[発注関連タイル表示]
    H -->|isCustomer| J[受注関連タイル表示]
    H -->|isManufacturer| K[製造元タイル表示]
    I --> L[タイル表示完了]
    J --> L
    K --> L
    L --> M{ユーザー操作}
    M -->|編集| N[編集フォーム]
    M -->|連絡先| O[外部アプリ起動]
    M -->|関連一覧| P[一覧画面へ遷移]
    M -->|注文作成| Q[作成フォーム]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-039-01 | 編集ボタン表示 | 会社の編集権限がある場合のみ編集ボタンを表示 | InvenTreeCompany().canEdit |
| BR-039-02 | 発注作成ボタン | サプライヤーかつ発注作成権限がある場合のみ表示 | isSupplier && canCreate |
| BR-039-03 | 受注作成ボタン | 顧客かつ受注作成権限がある場合のみ表示 | isCustomer && canCreate |
| BR-039-04 | 非アクティブ警告 | 会社がアクティブでない場合は警告タイルを表示 | !active |
| BR-039-05 | サプライヤーパーツ表示 | サプライヤーかつサプライヤーパーツ数が0より大きい場合のみ表示 | isSupplier && count > 0 |
| BR-039-06 | 発注カウント | サプライヤーの場合のみ未処理発注数をカウント | isSupplier |
| BR-039-07 | 受注カウント | 顧客の場合のみ未処理受注数をカウント | isCustomer |

### 計算ロジック

未処理発注/受注のカウント:
```dart
// サプライヤーの場合
outstandingPurchaseOrders = await InvenTreePurchaseOrder().count(
  filters: {
    "supplier": company.pk.toString(),
    "outstanding": "true",
  },
);

// 顧客の場合
outstandingSalesOrders = await InvenTreeSalesOrder().count(
  filters: {
    "customer": company.pk.toString(),
    "outstanding": "true",
  },
);
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 詳細取得 | company_company | SELECT | 会社詳細情報取得 |
| 編集 | company_company | UPDATE | 会社情報更新 |
| 発注カウント | order_purchaseorder | SELECT | 未処理発注数カウント |
| 受注カウント | order_salesorder | SELECT | 未処理受注数カウント |

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

#### company_company

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全カラム | pk = 指定ID | - |
| UPDATE | name, description, website, email, phone等 | フォーム入力値 | 編集時 |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

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

## パフォーマンス要件

- 初回表示時に会社データをリロード
- 発注・受注カウント、サプライヤーパーツ数、パラメータ数、添付ファイル数は非同期で取得

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

- APIアクセスには認証トークンが必要
- 会社の閲覧には適切な権限が必要
- 編集操作には編集権限が必要
- 外部リンクへのアクセスはopenLink()で処理

## 備考

- ウェブサイト、メール、電話のタップはそれぞれ外部アプリを起動
- 製造元パーツの表示は未実装（TODO）
- ノートはnotesプロパティで直接表示（編集機能なし）

---

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

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

### 推奨読解順序

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

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

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

**読解のコツ**: InvenTreeCompanyはInvenTreeModelを継承している。image, thumbnailはjsondataから取得。getPurchaseOrders()で発注リストを取得できる。

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

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

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

**主要処理フロー**:
1. **26-33行目**: CompanyDetailWidgetクラス定義
2. **35-44行目**: State変数（supplierPartCount, outstandingPurchaseOrders等）
3. **46-55行目**: getAppBarTitle()。会社名を含むタイトル
4. **57-74行目**: appBarActions()。編集ボタン構築
5. **76-105行目**: actionButtons()。発注・受注作成ボタン

#### Step 3: データ読み込み処理を理解する

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

**主要処理フロー**:
- **154-160行目**: company.reload()とエラー時のpop
- **162-170行目**: 未処理発注数のカウント（サプライヤーの場合）
- **172-179行目**: 未処理受注数のカウント（顧客の場合）
- **181-209行目**: サプライヤーパーツ数、パラメータ数、添付ファイル数の非同期カウント

#### Step 4: 画面タイル構築を理解する

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

**主要処理フロー**:
- **232-240行目**: ヘッダーカード（名前、説明、画像）
- **242-253行目**: 非アクティブ警告
- **255-269行目**: ウェブサイトタイル（openLink）
- **271-285行目**: メールタイル（mailto:）
- **287-301行目**: 電話タイル（tel:）
- **303-318行目**: 外部リンクタイル
- **324-342行目**: サプライヤーパーツタイル
- **344-361行目**: 発注タイル
- **379-396行目**: 受注タイル

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

```
CompanyDetailWidget
    │
    └─ _CompanyDetailState
           ├─ getAppBarTitle() → "Company - {name}"
           ├─ appBarActions() → 編集ボタン
           │      └─ editCompany() → editForm表示
           │
           ├─ actionButtons()
           │      ├─ _createSalesOrder() → 受注作成（顧客）
           │      └─ _createPurchaseOrder() → 発注作成（サプライヤー）
           │
           ├─ request()
           │      ├─ company.reload()
           │      ├─ InvenTreePurchaseOrder().count()
           │      ├─ InvenTreeSalesOrder().count()
           │      ├─ InvenTreeSupplierPart().count()
           │      ├─ InvenTreeParameter().countParameters()
           │      └─ InvenTreeAttachment().countAttachments()
           │
           └─ getTiles()
                  ├─ ヘッダーカード
                  ├─ 非アクティブ警告（!active）
                  ├─ ウェブサイト → openLink()
                  ├─ メール → openLink(mailto:)
                  ├─ 電話 → openLink(tel:)
                  ├─ 外部リンク → openLink()
                  ├─ サプライヤーパーツ → SupplierPartList
                  ├─ 発注 → PurchaseOrderListWidget
                  ├─ 受注 → SalesOrderListWidget
                  ├─ ノート
                  ├─ パラメータ → ShowParametersItem
                  └─ 添付ファイル → ShowAttachmentsItem
```

### データフロー図

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

会社オブジェクト ───▶ CompanyDetailWidget
    │                       │
    │                       ▼
    │                   request()
    │                       │
    │               ┌───────┴───────┐
    │               ▼               ▼
    │       company.reload()   非同期カウント取得
    │               │               │
    │               ▼               ▼
    │       会社詳細情報        発注数
    │                          受注数
    │                          サプライヤーパーツ数
    │                          パラメータ数
    │                          添付ファイル数
    │                               │
    └───────────────────────────────┘
                    │
                    ▼
            getTiles() 構築
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
    連絡先タイル   関連一覧    添付・パラメータ
    (web/email/   タイル      タイル
     phone/link)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| company_detail.dart | `lib/widget/company/company_detail.dart` | ソース | 会社詳細ウィジェット |
| company.dart | `lib/inventree/company.dart` | ソース | 会社データモデル |
| purchase_order_list.dart | `lib/widget/order/purchase_order_list.dart` | ソース | 発注一覧画面 |
| sales_order_list.dart | `lib/widget/order/sales_order_list.dart` | ソース | 受注一覧画面 |
| supplier_part_list.dart | `lib/widget/company/supplier_part_list.dart` | ソース | サプライヤーパーツ一覧 |
| purchase_order.dart | `lib/inventree/purchase_order.dart` | ソース | 発注データモデル |
| sales_order.dart | `lib/inventree/sales_order.dart` | ソース | 受注データモデル |
| attachment.dart | `lib/inventree/attachment.dart` | ソース | 添付ファイル管理 |
| parameter.dart | `lib/inventree/parameter.dart` | ソース | パラメータ管理 |
| attachment_widget.dart | `lib/widget/attachment_widget.dart` | ソース | 添付ファイルウィジェット |
| parameter_widget.dart | `lib/widget/parameter_widget.dart` | ソース | パラメータウィジェット |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | リフレッシュ可能State基底クラス |
| helpers.dart | `lib/helpers.dart` | ソース | openLink()等のヘルパー関数 |
