# 機能設計書 28-発注発行

## 概要

本ドキュメントは、InvenTreeアプリにおける発注発行（Issue）機能の設計を記載する。保留中（Pending）の発注をサプライヤーに発行（Placed）状態に変更する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：発注業務において、発注内容を確定しサプライヤーに正式に発注を行うことは重要なワークフローステップである。本機能により、発注を「保留中」から「発行済み」状態に変更し、受入処理が可能な状態にする。

**機能の利用シーン**：発注詳細画面で明細の追加・確認が完了し、サプライヤーへ正式に発注を送付する際に利用される。発注が「発行済み」になることで、受入処理（Receive）が有効になる。

**主要な処理内容**：
1. 発注詳細画面から発行処理を起動
2. 確認ダイアログを表示
3. ユーザー確認後、APIを通じて発注ステータスを更新
4. 更新成功後に画面をリフレッシュ

**関連システム・外部連携**：InvenTree REST API（`order/po/{pk}/issue/`エンドポイント）のPOSTメソッドと連携。

**権限による制御**：`purchase_order`ロールを持ち、かつcanCreate権限を持つユーザーのみ発行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 27 | 購入注文詳細画面 | 主画面 | 発行ボタン押下時に発注発行確認ダイアログ表示 |

## 機能種別

ステータス更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| order_pk | int | Yes | 発注ID | 正の整数（URL内で指定） |

### 入力データソース

発注詳細画面で表示中の`InvenTreePurchaseOrder`オブジェクトからPKを取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 発行成功フラグ |
| status | int | 更新後のステータスコード（PLACED） |

### 出力先

APIレスポンス → 画面リフレッシュ

## 処理フロー

### 処理シーケンス

```
1. 発行ボタン押下
   └─ _issueOrder()メソッド呼び出し
2. 確認ダイアログ表示
   └─ confirmationDialog()でユーザー確認
3. ユーザー承諾
   └─ onAcceptコールバック実行
4. API呼び出し
   ├─ order.issueOrder()メソッド実行
   └─ POST order/po/{pk}/issue/ エンドポイント
5. 発行成功
   └─ refresh()で画面リフレッシュ
```

### フローチャート

```mermaid
flowchart TD
    A[発行ボタン押下] --> B[_issueOrder呼び出し]
    B --> C[confirmationDialog表示]
    C --> D{ユーザー承諾?}
    D -->|Yes| E[order.issueOrder呼び出し]
    D -->|No| F[処理中断]
    E --> G[showLoadingOverlay]
    G --> H[API POST送信]
    H --> I[hideLoadingOverlay]
    I --> J{発行成功?}
    J -->|Yes| K[refresh呼び出し]
    J -->|No| L[エラー表示]
    K --> M[ステータス更新表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-28-01 | 保留中のみ発行可 | 発注が保留中（Pending/On Hold）状態の場合のみ発行可能 | isPending == true |
| BR-28-02 | 発行後の状態変化 | 発行後は「Placed」状態となり、受入処理が可能になる | - |
| BR-28-03 | 発行後の明細追加不可 | 発行後は明細の追加ができなくなる | - |
| BR-28-04 | 確認ダイアログ必須 | 発行前に必ず確認ダイアログを表示 | 常時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ステータス更新 | purchase_order | UPDATE | ステータスをPLACEDに変更 |

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

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

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | status | PLACED | ステータス変更 |
| UPDATE | issue_date | 現在日時 | 発行日時設定 |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

ネットワークエラー時はユーザーが再度発行ボタンを押下することでリトライ可能。

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

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

## パフォーマンス要件

- 発行処理中はローディングオーバーレイを表示
- 発行完了後は即座に画面をリフレッシュ

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

- トークンベース認証による保護
- canCreate権限チェックによるアクセス制御
- 確認ダイアログによる誤操作防止

## 備考

- 発行ボタンは`actionButtons`で構築される（119-127行目）
- 発行アイコンはTablerIcons.send（青色）
- 確認ダイアログのacceptTextは`L10().issue`
- APIレスポンスの期待ステータスコードは201

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | purchase_order.dart | `lib/inventree/purchase_order.dart` | isPendingプロパティ（108-109行目） |
| 1-2 | purchase_order.dart | `lib/inventree/purchase_order.dart` | issueOrderメソッド（136-145行目） |

**読解のコツ**: `isPending`は`api.PurchaseOrderStatus.isNameIn`で["PENDING", "ON_HOLD"]を判定。`issueOrder`はPOSTリクエストを送信する単純なメソッド。

#### Step 2: UI処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | actionButtonsメソッド（119-127行目） |
| 2-2 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | _issueOrderメソッド（191-204行目） |

**主要処理フロー**:
1. **119-127行目**: isPending時に発行ボタンをactionButtonsに追加
2. **191行目**: `_issueOrder`メソッド定義
3. **192-203行目**: confirmationDialogで確認後、issueOrder呼び出し

#### Step 3: API処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | purchase_order.dart | `lib/inventree/purchase_order.dart` | issueOrderメソッド（136-145行目） |

**主要処理フロー**:
- **137-139行目**: isPending条件チェック
- **141行目**: showLoadingOverlay()でローディング表示
- **142行目**: api.post("${url}issue/")でAPI呼び出し
- **143行目**: hideLoadingOverlay()でローディング非表示

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

```
PurchaseOrderDetailWidget
    │
    └─ _PurchaseOrderDetailState
           │
           ├─ actionButtons()
           │      │
           │      └─ SpeedDialChild（発行ボタン）
           │             │
           │             └─ condition: order.isPending
           │             └─ onTap → _issueOrder()
           │
           └─ _issueOrder()
                  │
                  └─ confirmationDialog()
                         │
                         └─ onAccept
                                │
                                └─ order.issueOrder()
                                       │
                                       ├─ isPending check
                                       ├─ showLoadingOverlay()
                                       ├─ api.post("${url}issue/")
                                       ├─ hideLoadingOverlay()
                                       │
                                       └─ .then()
                                              │
                                              └─ refresh()
```

### データフロー図

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

発行ボタン押下 ─────────▶ _issueOrder()
                               │
                               ▼
                      confirmationDialog()
                               │
                               ▼
                        ユーザー承諾
                               │
                               ▼
                      order.issueOrder()
                               │
                               ▼
               API: POST order/po/{pk}/issue/
                               │
                               ▼
                        ステータス更新
                        (PENDING → PLACED)
                               │
                               ▼
                          refresh()
                               │
                               ▼
                        画面更新表示
              (発行ボタン消去、受入ボタン表示)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | ソース | 発注詳細・発行処理ウィジェット |
| purchase_order.dart | `lib/inventree/purchase_order.dart` | ソース | 発注モデル・issueOrderメソッド |
| dialogs.dart | `lib/widget/dialogs.dart` | ソース | 確認ダイアログ |
| progress.dart | `lib/widget/progress.dart` | ソース | ローディングオーバーレイ |
| api.dart | `lib/api.dart` | ソース | API通信処理 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応 |
