# 機能設計書 29-発注完了

## 概要

本ドキュメントは、InvenTreeアプリにおける発注完了機能の設計を記載する。発行済み（Placed）の発注を完了（Complete）状態に変更する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：発注業務において、全ての品目の受入が完了した際に発注をクローズすることは重要なワークフローステップである。本機能により、発注を「完了」状態に変更し、発注サイクルを終了させる。未完了の明細がある場合でも強制完了が可能。

**機能の利用シーン**：発注詳細画面で全ての品目を受入完了した後、または一部未受入のまま発注をクローズする際に利用される。発注が「完了」状態になることで、以降の受入処理はできなくなる。

**主要な処理内容**：
1. 発注詳細画面から完了処理を起動
2. 完了フォーム（未完了品の受入オプション付き）を表示
3. ユーザー確認後、APIを通じて発注ステータスを更新
4. 更新成功後に画面をリフレッシュ

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

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 27 | 購入注文詳細画面 | 主画面 | 完了ボタン押下時に発注完了フォーム表示 |

## 機能種別

ステータス更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| order_pk | int | Yes | 発注ID | 正の整数（URL内で指定） |
| accept_incomplete | bool | No | 未完了品を受け入れるか | デフォルトfalse |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 完了ボタン押下
   └─ _completeOrder()メソッド呼び出し
2. フォーム準備
   └─ accept_incompleteフィールドを定義
3. フォーム表示
   └─ launchApiForm()でダイアログ表示
4. ユーザー入力
   └─ 未完了品受入オプションを選択
5. API呼び出し
   └─ POST order/po/{pk}/complete/ エンドポイント
6. 完了成功
   └─ refresh()で画面リフレッシュ
```

### フローチャート

```mermaid
flowchart TD
    A[完了ボタン押下] --> B[_completeOrder呼び出し]
    B --> C[フィールド定義]
    C --> D[launchApiForm呼び出し]
    D --> E[フォームダイアログ表示]
    E --> F{未完了品あり?}
    F -->|Yes| G[accept_incomplete選択]
    F -->|No| H[そのまま完了]
    G --> I[完了ボタン押下]
    H --> I
    I --> J[API POST送信]
    J --> K{完了成功?}
    K -->|Yes| L[refresh呼び出し]
    K -->|No| M[エラー表示]
    L --> N[ステータス更新表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-29-01 | オープン状態のみ完了可 | 発注がオープン状態（Placed）の場合のみ完了可能 | isOpen && !isPending |
| BR-29-02 | 未完了品オプション | 未完了の明細がある場合、accept_incompleteで強制完了可能 | 未完了明細あり |
| BR-29-03 | 完了後の状態変化 | 完了後は「Complete」状態となり、受入処理ができなくなる | - |
| BR-29-04 | 完了後の編集不可 | 完了後は発注の編集ができなくなる | - |

### 計算ロジック

特になし。

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

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

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

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

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

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

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

## パフォーマンス要件

- フォーム表示は即座に行う
- 完了処理中はローディングを表示

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

- トークンベース認証による保護
- canCreate権限チェックによるアクセス制御
- フォームによる確認操作で誤完了を防止

## 備考

- 完了ボタンは`actionButtons`で構築される（130-139行目）
- 完了アイコンはTablerIcons.circle_check（緑色）
- フォームを使用するため確認ダイアログではなくlaunchApiFormを使用
- accept_incompleteオプションで未完了品を受け入れて完了可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | purchase_order.dart | `lib/inventree/purchase_order.dart` | isOpenプロパティ（102-106行目） |
| 1-2 | purchase_order.dart | `lib/inventree/purchase_order.dart` | isPendingプロパティ（108-109行目） |

**読解のコツ**: `isOpen`は["PENDING", "PLACED", "ON_HOLD"]を含む。完了ボタンは`isOpen && !isPending`（つまりPLACEDかON_HOLD）で表示。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | actionButtonsメソッド（130-139行目） |
| 2-2 | purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | _completeOrderメソッド（207-222行目） |

**主要処理フロー**:
1. **130行目**: `isOpen && !isPending`条件で完了ボタン表示
2. **207行目**: `_completeOrder`メソッド定義
3. **208行目**: accept_incompleteフィールド定義
4. **210行目**: エンドポイントURL構築
5. **212-221行目**: launchApiFormでフォーム表示

#### Step 3: API通信を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | api_form.dart | `lib/api_form.dart` | launchApiForm関数 |

**主要処理フロー**:
- launchApiFormはフォームダイアログを表示し、POSTリクエストを送信
- method: "POST"で明示的にPOSTメソッドを指定

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

```
PurchaseOrderDetailWidget
    │
    └─ _PurchaseOrderDetailState
           │
           ├─ actionButtons()
           │      │
           │      └─ SpeedDialChild（完了ボタン）
           │             │
           │             └─ condition: isOpen && !isPending
           │             └─ onTap → _completeOrder()
           │
           └─ _completeOrder()
                  │
                  ├─ fields定義
                  │      └─ "accept_incomplete": {}
                  │
                  ├─ URL構築
                  │      └─ "order/po/${pk}/complete/"
                  │
                  └─ launchApiForm()
                         │
                         ├─ method: "POST"
                         │
                         └─ onSuccess
                                │
                                └─ refresh()
```

### データフロー図

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

完了ボタン押下 ─────────▶ _completeOrder()
                               │
                               ▼
                      fields定義
                      (accept_incomplete)
                               │
                               ▼
                      launchApiForm()
                               │
                               ▼
                   [フォームダイアログ]
                               │
                               ▼
           ユーザー選択（accept_incomplete）
                               │
                               ▼
             API: POST order/po/{pk}/complete/
                               │
                               ▼
                        ステータス更新
                      (PLACED → COMPLETE)
                               │
                               ▼
                          refresh()
                               │
                               ▼
                        画面更新表示
            (完了ボタン消去、受入ボタン消去)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| purchase_order_detail.dart | `lib/widget/order/purchase_order_detail.dart` | ソース | 発注詳細・完了処理ウィジェット |
| purchase_order.dart | `lib/inventree/purchase_order.dart` | ソース | 発注モデル |
| api_form.dart | `lib/api_form.dart` | ソース | APIフォーム・通信処理 |
| api.dart | `lib/api.dart` | ソース | API通信処理 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応 |
