# 機能設計書 23-発注一覧表示

## 概要

本ドキュメントは、InvenTreeアプリにおける発注（Purchase Order）一覧表示機能の設計を記載する。サプライヤーへの発注を一覧形式で表示し、発注管理の起点となる機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：調達業務において、発注の状態を一覧で把握し、未処理・処理中・完了済みの発注を効率的に管理することは必須である。本機能により、全ての発注を一元的に確認し、詳細画面への遷移や新規発注の作成が可能となる。

**機能の利用シーン**：ホーム画面やドロワーメニューから発注一覧にアクセスし、発注状況を確認する。また、サプライヤー詳細画面から特定サプライヤーの発注のみをフィルタ表示することも可能。

**主要な処理内容**：
1. APIから発注データをページネーション形式で取得
2. 各発注のリファレンス、説明、サプライヤー、ステータスを表示
3. フィルタ・ソート機能による絞り込み
4. 新規発注作成機能の提供
5. バーコードスキャンによる受入機能の提供

**関連システム・外部連携**：InvenTree REST API（`order/po/`エンドポイント）と連携。バーコードスキャン機能ではカメラ/ウェッジスキャナと連携。

**権限による制御**：`purchase_order`ロールを持つユーザーが閲覧可能。新規作成にはcanCreate権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ホーム画面 | 遷移元画面 | 発注タイル押下時に発注一覧画面へ遷移 |
| 2 | ドロワーメニュー | 遷移元画面 | 発注メニュー押下時に発注一覧画面へ遷移 |
| 3 | 検索画面 | 遷移元画面 | 発注検索結果押下時に発注一覧画面へ遷移 |
| 26 | 購入注文一覧画面 | 主画面 | 発注のページネーション付き一覧表示 |
| 27 | 購入注文詳細画面 | 遷移先画面 | 発注選択時に発注詳細画面へ遷移 |
| 31 | 会社詳細画面 | 遷移元画面 | 発注項目押下時に発注一覧画面へ遷移（サプライヤーフィルタ） |

## 機能種別

データ参照 / 一覧表示 / 新規作成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filters | Map<String, String> | No | フィルタ条件（supplier等） | - |
| limit | int | No | 取得件数上限 | デフォルト25件 |
| offset | int | No | 取得開始位置 | デフォルト0 |
| outstanding | bool | No | 未完了のみ表示 | デフォルトtrue |
| overdue | bool | No | 期限超過のみ表示 | - |
| assigned_to_me | bool | No | 自分担当のみ表示 | - |

### 入力データソース

画面遷移時のフィルタパラメータ、設定からの保存済みフィルタ値。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| reference | String | 発注リファレンス番号 |
| description | String | 発注の説明 |
| supplier | InvenTreeCompany | サプライヤー情報 |
| status | int | 発注ステータスコード |
| statusLabel | String | ステータス表示ラベル |

### 出力先

画面（リストビュー形式）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ PurchaseOrderListWidgetがフィルタを受け取る
2. データ取得（requestPage）
   ├─ PurchaseOrderStatus.load()でステータスコードロード
   └─ InvenTreePurchaseOrder().listPaginated()で発注取得
3. 一覧表示
   └─ 各発注をListTileで表示（サムネイル、リファレンス、ステータス）
4. ユーザー操作
   ├─ タップ → 詳細画面へ遷移
   ├─ 追加ボタン → 新規作成フォーム
   └─ バーコードボタン → 受入スキャン
```

### フローチャート

```mermaid
flowchart TD
    A[ホーム/メニューから遷移] --> B[PurchaseOrderListWidget初期化]
    B --> C[PaginatedPurchaseOrderList生成]
    C --> D[requestPage呼び出し]
    D --> E[PurchaseOrderStatus.load]
    E --> F[listPaginated API呼び出し]
    F --> G{データ取得成功?}
    G -->|Yes| H[buildItemで各発注を描画]
    G -->|No| I[エラー表示]
    H --> J[ユーザー操作待機]
    J --> K{操作種別}
    K -->|タップ| L[goToDetailPage]
    K -->|追加| M[_createPurchaseOrder]
    K -->|バーコード| N[scanBarcode]
    L --> O[詳細画面]
    M --> P[createForm表示]
    N --> Q[POReceiveBarcodeHandler]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-23-01 | デフォルト未完了表示 | outstandingフィルタのデフォルトはtrue | 初回表示時 |
| BR-23-02 | ステータス色分け | ステータスに応じて色を変更 | 常時 |
| BR-23-03 | サプライヤーサムネイル | サプライヤーがある場合のみサムネイル表示 | supplier != null |
| BR-23-04 | バーコード受入 | API v139以上でバーコード受入ボタン表示 | supportsBarcodePOReceiveEndpoint |
| BR-23-05 | 新規作成権限 | canCreateがtrueの場合のみ追加ボタン表示 | canCreate == true |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | purchase_order | SELECT | 発注一覧を取得 |
| 新規作成 | purchase_order | INSERT | 新規発注を登録 |

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

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

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | supplier_detail | true | サプライヤー詳細を含む |
| SELECT | outstanding | true/false | 未完了フィルタ |
| SELECT | overdue | true/false | 期限超過フィルタ |
| INSERT | reference | :reference | 発注リファレンス |
| INSERT | supplier | :supplierId | サプライヤーID |
| INSERT | description | :description | 説明 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | トークン無効 | 再ログインを促す |
| 403 | 権限エラー | purchase_orderロール未付与 | 権限不足メッセージ表示 |
| 400 | バリデーションエラー | 必須項目未入力 | フォームにエラー表示 |
| 500 | サーバーエラー | サーバー側障害 | リトライを促す |

### リトライ仕様

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

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

新規作成はAPI側で単一トランザクションとして処理される。

## パフォーマンス要件

- 1ページあたり25件を取得
- 無限スクロールによる遅延読み込み
- サプライヤーサムネイルはキャッシュから取得

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

- トークンベース認証による保護
- purchase_orderロールを持つユーザーのみアクセス可能

## 備考

- ソートオプション: reference, supplier__name, status, target_date
- フィルタオプション: outstanding, overdue, assigned_to_me
- 新規作成時はcontactフィールドを除外（サプライヤー確定後に設定可能）

---

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

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

### 推奨読解順序

#### 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行目） |

**読解のコツ**: `InvenTreePurchaseOrder`は`InvenTreeOrder`を継承し、発注固有のプロパティ（supplierId、isPending、isPlaced等）を定義している。

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

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

**主要処理フロー**:
1. **19-28行目**: StatefulWidgetの定義、フィルタをコンストラクタで受け取る
2. **38-54行目**: actionButtonsで新規作成ボタンを構築
3. **57-76行目**: _createPurchaseOrderで新規発注フォーム表示
4. **79-95行目**: barcodeButtonsでバーコード受入ボタンを構築

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | purchase_order_list.dart | `lib/widget/order/purchase_order_list.dart` | PaginatedPurchaseOrderListとその状態クラス（103-187行目） |

**主要処理フロー**:
- **123-128行目**: orderingOptionsでソートオプション定義
- **131-148行目**: filterOptionsでフィルタオプション定義
- **151-164行目**: requestPageでAPIからデータ取得
- **167-186行目**: buildItemでListTile構築

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

```
PurchaseOrderListWidget
    │
    ├─ _PurchaseOrderListWidgetState
    │      │
    │      ├─ actionButtons()
    │      │      └─ SpeedDialChild（新規作成）
    │      │
    │      ├─ barcodeButtons()
    │      │      └─ SpeedDialChild（バーコード受入）
    │      │
    │      ├─ _createPurchaseOrder()
    │      │      └─ InvenTreePurchaseOrder().createForm()
    │      │
    │      └─ getBody()
    │             └─ PaginatedPurchaseOrderList生成
    │
    └─ PaginatedPurchaseOrderList
           │
           └─ _PaginatedPurchaseOrderListState
                  │
                  ├─ requestPage()
                  │      ├─ PurchaseOrderStatus.load()
                  │      └─ InvenTreePurchaseOrder().listPaginated()
                  │
                  └─ buildItem()
                         └─ ListTile構築 → onTap → goToDetailPage()
```

### データフロー図

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

filters (Map) ────────▶ PurchaseOrderListWidget
                               │
                               ▼
                      PaginatedPurchaseOrderList
                               │
                               ▼
                      requestPage() ───▶ API: order/po/
                               │
                               ▼
                    InvenTreePurchaseOrder[]
                               │
                               ▼
                         buildItem()
                               │
                               ▼
                          ListTile[]
            (サムネイル・リファレンス・説明・ステータス)
                               │
                               ▼
                     onTap → goToDetailPage()
                               │
                               ▼
                    PurchaseOrderDetailWidget
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| purchase_order_list.dart | `lib/widget/order/purchase_order_list.dart` | ソース | 発注一覧ウィジェット |
| purchase_order.dart | `lib/inventree/purchase_order.dart` | ソース | 発注モデル定義 |
| orders.dart | `lib/inventree/orders.dart` | ソース | オーダー基底モデル |
| paginator.dart | `lib/widget/paginator.dart` | ソース | ページネーション基底クラス |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | 更新可能な状態の基底クラス |
| barcode.dart | `lib/barcode/barcode.dart` | ソース | バーコードスキャン処理 |
| purchase_order.dart | `lib/barcode/purchase_order.dart` | ソース | 発注バーコードハンドラ |
| api.dart | `lib/api.dart` | ソース | API通信処理 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応 |
