# 機能設計書 24-発注詳細表示

## 概要

本ドキュメントは、InvenTreeアプリにおける発注（Purchase Order）詳細表示機能の設計を記載する。個々の発注の詳細情報を表示し、発注に関する全ての情報へのアクセスポイントを提供する。

### 本機能の処理概要

**業務上の目的・背景**：調達業務において、発注の詳細情報（サプライヤー、明細、受入状況、添付ファイル等）を一箇所で確認できることは業務効率化に直結する。本機能により、発注に関する全ての情報を統合的に表示し、関連する操作（編集、発行、完了、キャンセル等）へのアクセスを提供する。

**機能の利用シーン**：発注一覧画面から特定の発注を選択した際、または検索結果やバーコードスキャンから発注にアクセスした際に利用される。発注の状態確認、明細の確認、受入状況の追跡などに活用。

**主要な処理内容**：
1. 発注の基本情報（リファレンス、サプライヤー、ステータス等）を表示
2. 明細行の一覧をタブで表示
3. 受入済み在庫アイテムの一覧をタブで表示
4. 添付ファイル、ノート、パラメータへのリンクを提供
5. 発注状態に応じたアクションボタンを提供

**関連システム・外部連携**：InvenTree REST API（`order/po/`、`order/po-line/`エンドポイント等）と連携。

**権限による制御**：`purchase_order`ロールを持つユーザーが閲覧可能。編集にはcanEdit権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 購入注文一覧画面 | 遷移元画面 | 発注選択時に発注詳細画面へ遷移 |
| 5 | バーコードスキャン画面 | 遷移元画面 | 発注バーコード照合成功時に発注詳細画面へ遷移 |
| 27 | 購入注文詳細画面 | 主画面 | 発注の詳細情報表示 |

## 機能種別

データ参照 / 詳細表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| order | InvenTreePurchaseOrder | Yes | 表示対象の発注オブジェクト | - |

### 入力データソース

発注一覧画面や検索結果から渡される`InvenTreePurchaseOrder`オブジェクト。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| reference | String | 発注リファレンス番号 |
| description | String | 発注の説明 |
| supplier | InvenTreeCompany | サプライヤー情報 |
| supplierReference | String | サプライヤー参照番号 |
| status | int | 発注ステータスコード |
| projectCode | String | プロジェクトコード |
| destination | InvenTreeStockLocation | 受入先ロケーション |
| lineItemCount | int | 明細行数 |
| completedLines | int | 完了した明細行数 |
| issueDate | String | 発行日 |
| startDate | String | 開始日 |
| targetDate | String | 目標日 |
| completionDate | String | 完了日 |
| totalPrice | double | 合計金額 |
| responsibleName | String | 担当者名 |

### 出力先

画面（タブ形式のレイアウト）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ PurchaseOrderDetailWidgetが発注オブジェクトを受け取る
2. データ取得（request）
   ├─ order.reload()で最新データ取得
   ├─ PurchaseOrderStatus.load()でステータスコードロード
   ├─ getLineItems()で明細行取得
   ├─ 設定からshowCameraShortcut取得
   ├─ countParameters()でパラメータ数取得
   ├─ countAttachments()で添付ファイル数取得
   ├─ destination取得（supportsPurchaseOrderDestination時）
   └─ 追加明細行数取得
3. タブ表示
   ├─ Detailsタブ: 基本情報タイル
   ├─ Line Itemsタブ: PaginatedPOLineList
   └─ Receivedタブ: PaginatedStockItemList
4. アクション提供
   ├─ 編集ボタン（canEdit時）
   ├─ カメラボタン（showCameraShortcut時）
   ├─ 明細追加ボタン（isPending時）
   ├─ 発行ボタン（isPending時）
   ├─ 完了ボタン（isOpen && !isPending時）
   └─ キャンセルボタン（isOpen時）
```

### フローチャート

```mermaid
flowchart TD
    A[発注一覧から遷移] --> B[PurchaseOrderDetailWidget初期化]
    B --> C[request呼び出し]
    C --> D[order.reload]
    D --> E[getLineItems]
    E --> F[各種カウント取得]
    F --> G[タブビュー構築]
    G --> H[Detailsタブ表示]
    G --> I[Line Itemsタブ表示]
    G --> J[Receivedタブ表示]
    H --> K[アクションボタン待機]
    K --> L{アクション種別}
    L -->|編集| M[editOrder]
    L -->|発行| N[_issueOrder]
    L -->|完了| O[_completeOrder]
    L -->|キャンセル| P[_cancelOrder]
    L -->|明細追加| Q[_addLineItem]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | 編集ボタン表示 | canEdit時のみ編集ボタン表示 | canEdit == true |
| BR-24-02 | 発行ボタン表示 | 保留中のみ発行ボタン表示 | isPending == true |
| BR-24-03 | 完了ボタン表示 | オープンかつ保留中でない時のみ完了ボタン表示 | isOpen && !isPending |
| BR-24-04 | キャンセルボタン表示 | オープン時のみキャンセルボタン表示 | isOpen == true |
| BR-24-05 | 明細追加ボタン表示 | 保留中のみ明細追加ボタン表示 | isPending == true |
| BR-24-06 | プロジェクトコード表示 | 有効かつ設定済みの場合のみ表示 | supportProjectCodes && hasProjectCode |
| BR-24-07 | 受入先表示 | destination設定済みの場合のみ表示 | destinationId > 0 |

### 計算ロジック

明細行の完了進捗を計算し、プログレスバーで表示。`completedLines / lineItemCount`で進捗率を算出。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 詳細取得 | purchase_order | SELECT | 発注詳細を取得 |
| 明細取得 | purchase_order_line | SELECT | 発注明細を取得 |
| 受入品取得 | stock_item | SELECT | 受入済み在庫を取得 |

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

#### purchase_order（APIエンドポイント: order/po/{pk}/）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | supplier_detail | true | サプライヤー詳細を含む |
| SELECT | project_code_detail | true | プロジェクトコード詳細を含む |
| SELECT | responsible_detail | true | 担当者詳細を含む |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | トークン無効 | 再ログインを促す |
| 403 | 権限エラー | purchase_orderロール未付与 | 権限不足メッセージ表示 |
| 404 | Not Found | 発注が存在しない | 一覧に戻る |
| 500 | サーバーエラー | サーバー側障害 | リトライを促す |

### リトライ仕様

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

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

参照のみのため、トランザクション管理不要。

## パフォーマンス要件

- 発注詳細と明細は非同期で並行取得
- パラメータ数・添付ファイル数は非同期で取得（UIをブロックしない）
- 明細行はページネーションで表示

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

- トークンベース認証による保護
- purchase_orderロールを持つユーザーのみアクセス可能
- 編集・発行・完了・キャンセル操作は権限チェック

## 備考

- タブ構成: Details, Line Items, Received
- プロジェクトコードはAPI v109以上で対応
- 受入先（destination）はAPI v276以上で対応
- 開始日（start_date）はAPI v306以上で対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | purchase_order.dart | `lib/inventree/purchase_order.dart` | InvenTreePurchaseOrderクラス（18-157行目） |
| 1-2 | orders.dart | `lib/inventree/orders.dart` | InvenTreeOrder基底クラス（11-81行目） |

**読解のコツ**: 発注状態の判定（isPending, isPlaced, isOpen, isFailed）は`api.PurchaseOrderStatus.isNameIn()`で行われる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | PurchaseOrderDetailWidgetの全体構造（36-632行目） |

**主要処理フロー**:
1. **36-43行目**: StatefulWidgetの定義
2. **61-70行目**: getAppBarTitleでタイトル設定
3. **73-89行目**: appBarActionsで編集ボタン設定
4. **92-156行目**: actionButtonsでアクションボタン群構築
5. **280-361行目**: requestで全データ取得

#### Step 3: タブ表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | getTabIconsとgetTabsメソッド（614-631行目） |
| 3-2 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | orderTilesメソッド（407-612行目） |

**主要処理フロー**:
- **614-621行目**: タブアイコン定義（Details, Line Items, Received）
- **623-631行目**: 各タブのコンテンツ構築
- **407-612行目**: Detailsタブの各タイル構築

#### Step 4: アクション処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | 各アクションメソッド（158-238行目） |

**主要処理フロー**:
- **159-177行目**: _addLineItemで明細追加
- **191-204行目**: _issueOrderで発注発行
- **207-222行目**: _completeOrderで発注完了
- **225-238行目**: _cancelOrderで発注キャンセル

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

```
PurchaseOrderDetailWidget
    │
    ├─ _PurchaseOrderDetailState
    │      │
    │      ├─ request()
    │      │      ├─ order.reload()
    │      │      ├─ api.PurchaseOrderStatus.load()
    │      │      ├─ order.getLineItems()
    │      │      ├─ InvenTreeParameter().countParameters()
    │      │      ├─ InvenTreeAttachment().countAttachments()
    │      │      ├─ InvenTreeStockLocation().get() [destination]
    │      │      └─ InvenTreePOExtraLineItem().count()
    │      │
    │      ├─ getTabIcons() / getTabs()
    │      │      ├─ orderTiles() [Details]
    │      │      ├─ PaginatedPOLineList [Line Items]
    │      │      └─ PaginatedStockItemList [Received]
    │      │
    │      ├─ actionButtons()
    │      │      ├─ _uploadImage()
    │      │      ├─ _addLineItem()
    │      │      ├─ _issueOrder()
    │      │      ├─ _completeOrder()
    │      │      └─ _cancelOrder()
    │      │
    │      ├─ barcodeButtons()
    │      │      ├─ POReceiveBarcodeHandler
    │      │      └─ POAllocateBarcodeHandler
    │      │
    │      └─ editOrder()
```

### データフロー図

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

InvenTreePurchaseOrder ────▶ PurchaseOrderDetailWidget
         │                           │
         ▼                           ▼
    order.pk ──────────────▶ API: order/po/{pk}/
                                     │
                                     ▼
                           InvenTreePurchaseOrder (更新)
                                     │
         ┌───────────────────────────┼───────────────────────────┐
         ▼                           ▼                           ▼
    orderTiles()             PaginatedPOLineList        PaginatedStockItemList
         │                           │                           │
         ▼                           ▼                           ▼
    Detailsタブ               Line Itemsタブ             Receivedタブ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | ソース | 発注詳細ウィジェット |
| purchase_order.dart | `lib/inventree/purchase_order.dart` | ソース | 発注モデル定義 |
| orders.dart | `lib/inventree/orders.dart` | ソース | オーダー基底モデル |
| po_line_list.dart | `lib/widget/order/po_line_list.dart` | ソース | 発注明細一覧 |
| po_extra_line_list.dart | `lib/widget/order/po_extra_line_list.dart` | ソース | 追加明細一覧 |
| stock_list.dart | `lib/widget/stock/stock_list.dart` | ソース | 在庫一覧 |
| attachment_widget.dart | `lib/widget/attachment_widget.dart` | ソース | 添付ファイル表示 |
| notes_widget.dart | `lib/widget/notes_widget.dart` | ソース | ノート表示 |
| parameter_widget.dart | `lib/widget/parameter_widget.dart` | ソース | パラメータ表示 |
| progress.dart | `lib/widget/progress.dart` | ソース | プログレスバー |
| dialogs.dart | `lib/widget/dialogs.dart` | ソース | 確認ダイアログ |
| api.dart | `lib/api.dart` | ソース | API通信処理 |
| api_form.dart | `lib/api_form.dart` | ソース | フォーム生成処理 |
