# 画面設計書 44-フルフィルメント作成画面

## 概要

本ドキュメントは、Medusa管理画面におけるフルフィルメント作成画面の設計を記載する。本画面は、注文に対するフルフィルメント（発送準備）を作成するためのモーダル形式の画面であり、在庫ロケーション、配送方法、発送対象商品の選択を行う。

### 本画面の処理概要

**業務上の目的・背景**：ECサイト運営において、注文を受けた後に商品を発送するためには、フルフィルメントの作成が必要である。本画面は、どの在庫ロケーションから、どの配送方法で、どの商品を発送するかを指定し、フルフィルメントを作成する機能を提供する。在庫管理との連携により、在庫の予約状況や利用可能在庫数も確認できる。

**画面へのアクセス方法**：注文詳細画面（/orders/{id}）のサマリーセクションまたはフルフィルメントセクションから「Create Fulfillment」アクションを選択することでアクセス。requires_shippingパラメータにより、配送が必要な商品か否かを区別する。

**主要な操作・処理内容**：
1. 在庫ロケーションの選択：商品を発送する倉庫・店舗を選択
2. 配送方法の選択：配送オプションを選択
3. フルフィルメント対象商品の確認・数量調整：発送する商品と数量を指定
4. 通知設定：顧客への通知を送信するかどうかを設定
5. フルフィルメントの作成：設定内容でフルフィルメントを作成

**画面遷移**：
- 遷移元：注文詳細画面（/orders/{id}）
- 遷移先：注文詳細画面（フルフィルメント作成完了後）

**権限による表示制御**：管理者権限を持つユーザーのみがアクセス可能。フルフィルメント可能な商品がない場合はエラー表示。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| F-001 | フルフィルメント作成 | 主機能 | フルフィルメントデータの作成 |
| F-002 | 在庫ロケーション取得 | 補助機能 | 利用可能な在庫ロケーション一覧取得 |
| F-003 | 配送オプション取得 | 補助機能 | 利用可能な配送オプション一覧取得 |
| F-004 | 在庫予約確認 | 補助機能 | 商品の在庫予約状況確認 |

## 画面種別

モーダル（RouteFocusModal）

## URL/ルーティング

```
/orders/:id/fulfillment?requires_shipping={true|false}
```

## 入出力項目

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| id | 入力 | string | ○ | 注文ID（URLパラメータ） |
| requires_shipping | 入力 | boolean | × | 配送が必要かどうか（URLパラメータ） |
| location_id | 入力 | string | ○ | 在庫ロケーションID |
| shipping_option_id | 入力 | string | ○ | 配送オプションID |
| quantity | 入力 | object | ○ | 商品ID別の発送数量 |
| send_notification | 入力 | boolean | × | 顧客への通知送信フラグ |

## 表示項目

| 項目名 | 表示名 | 型 | 説明 |
|--------|--------|-----|------|
| location_id | Location | select | 在庫ロケーション選択 |
| shipping_option_id | Shipping Method | select | 配送方法選択 |
| items | Items to Fulfill | list | フルフィルメント対象商品一覧 |
| items[].thumbnail | - | image | 商品サムネイル |
| items[].title | Title | string | 商品名 |
| items[].variant_sku | SKU | string | バリアントSKU |
| items[].quantity | Quantity | number | 発送数量（入力） |
| items[].fulfillable_quantity | Available | number | フルフィルメント可能数量 |
| items[].reserved_quantity | Reserved | number | 予約済み数量 |
| send_notification | Send Notification | switch | 通知送信スイッチ |

## イベント仕様

### 1-在庫ロケーション選択

Comboboxで在庫ロケーションを選択すると、該当ロケーションで利用可能な配送オプションが絞り込まれる。

- 処理: `location_id`フィールドの更新
- 連動: 配送オプションのフィルタリング

### 2-配送方法選択

Selectで配送方法を選択する。選択された配送方法のshipping_profile_idに基づき、対象商品がフィルタリングされる。

- 処理: `shipping_option_id`フィールドの更新
- 警告: 元の注文と異なる配送オプションを選択した場合、警告アラートを表示

### 3-数量変更

各商品の発送数量を変更する。

- バリデーション: 0以上、フルフィルメント可能数量以下
- 処理: `quantity[item_id]`フィールドの更新

### 4-フルフィルメント作成

「Create Fulfillment」ボタンをクリックすると、フルフィルメントが作成される。

- バリデーション:
  - 在庫ロケーションが選択されていること
  - 配送オプションが選択されていること
  - 少なくとも1つの商品が選択されていること
- API呼び出し: `POST /admin/orders/{id}/fulfillments`
- リクエストボディ:
  ```json
  {
    "location_id": "loc_xxx",
    "shipping_option_id": "so_xxx",
    "no_notification": false,
    "items": [{ "id": "item_xxx", "quantity": 1 }]
  }
  ```
- 成功時: トースト通知で成功メッセージを表示し、注文詳細画面へ遷移
- エラー時: トースト通知でエラーメッセージを表示

### 5-キャンセル

「Cancel」ボタンをクリックすると、モーダルを閉じて注文詳細画面に戻る。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | order | SELECT | 注文データの取得 |
| 画面表示 | stock_location | SELECT | 在庫ロケーション一覧取得 |
| 画面表示 | shipping_option | SELECT | 配送オプション一覧取得 |
| 画面表示 | reservation_item | SELECT | 在庫予約情報取得 |
| フルフィルメント作成 | fulfillment | INSERT | フルフィルメントの作成 |
| フルフィルメント作成 | fulfillment_item | INSERT | フルフィルメント対象商品の登録 |
| フルフィルメント作成 | order | UPDATE | fulfillment_statusの更新 |

### テーブル別更新項目詳細

#### fulfillment

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | order_id | 注文ID | 対象注文 |
| INSERT | location_id | 選択されたロケーションID | 出荷元ロケーション |
| INSERT | shipping_option_id | 選択された配送オプションID | 配送方法 |
| INSERT | status | "pending" | 初期ステータス |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| orders.fulfillment.toast.created | 成功 | Fulfillment created | フルフィルメント作成成功時 |
| orders.fulfillment.error.noShippingOption | エラー | No shipping option selected | 配送オプション未選択時 |
| orders.fulfillment.error.noLocation | エラー | No location selected | ロケーション未選択時 |
| orders.fulfillment.error.noItems | エラー | No items to fulfill | フルフィルメント対象商品なし |
| orders.fulfillment.differentOptionSelected | 警告 | Different shipping option selected | 元の注文と異なる配送オプション選択時 |
| エラーメッセージ | エラー | API返却のエラーメッセージ | API呼び出しエラー時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 注文が見つからない | エラーをthrowしてエラーバウンダリで処理 |
| フルフィルメント可能商品なし | rootエラーとして表示 |
| API呼び出しエラー | トースト通知でエラーメッセージを表示 |
| 認証エラー | ログイン画面へリダイレクト |

## 備考

- requires_shippingパラメータにより、配送が必要な商品と不要な商品を区別してフルフィルメントを作成できる
- shipping_profile_idに基づき、対象商品がフィルタリングされる
- 在庫予約情報は`getReservationsLimitCount`関数で計算されるlimit件数分取得される
- useComboboxDataを使用して在庫ロケーションの検索が可能

---

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

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

### 推奨読解順序

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

まず、フルフィルメント作成に必要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/constants.ts` | CreateFulfillmentSchemaでバリデーションスキーマを確認 |

**読解のコツ**: zodスキーマを確認し、必須フィールドとバリデーションルールを把握する。

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

処理の起点となるコンポーネントを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | order-create-fulfillments.tsx | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/order-create-fulfillments.tsx` | ページコンポーネントの構成を確認 |

**主要処理フロー**:
1. **行8-9**: `useParams`と`useSearchParams`でパラメータ取得
2. **行10**: `requires_shipping`パラメータを取得
3. **行12-15**: `useOrder`で注文データを取得（特定のfieldsを指定）
4. **行22-31**: `OrderCreateFulfillmentForm`コンポーネントをレンダリング

#### Step 3: フォームコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | order-create-fulfillment-form.tsx | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-form.tsx` | フォームの実装詳細 |

**主要処理フロー**:
- **行43-44**: `useCreateOrderFulfillment`でAPIフック取得
- **行46-49**: `useReservationItems`で在庫予約情報取得
- **行51-59**: `useComboboxData`で在庫ロケーションのコンボボックスデータ取得
- **行61-67**: `fulfillableItems`ステートでフルフィルメント可能商品を管理
- **行69-81**: `useForm`でフォーム状態を管理
- **行88-93**: `useShippingOptions`で配送オプション取得
- **行100-160**: `handleSubmit`でフルフィルメント作成処理

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

```
OrderCreateFulfillment (order-create-fulfillments.tsx)
    │
    ├─ useParams (注文ID)
    ├─ useSearchParams (requires_shipping)
    ├─ useOrder (注文データ)
    │
    └─ OrderCreateFulfillmentForm
           │
           ├─ useCreateOrderFulfillment (APIフック)
           ├─ useReservationItems (在庫予約)
           ├─ useComboboxData (在庫ロケーション)
           ├─ useShippingOptions (配送オプション)
           ├─ useForm (フォーム状態)
           │
           └─ handleSubmit
                  └─ createOrderFulfillment → API呼び出し
```

### データフロー図

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

URLパラメータ ───▶ useParams/useSearchParams ▶ id, requires_shipping
                          │
                          ▼
注文ID ──────────▶ useOrder ──────────────▶ order
                          │
                          ▼
order ───────────▶ fulfillableItems算出 ──▶ フルフィルメント可能商品
                          │
                          ▼
フォーム入力 ────▶ handleSubmit ───────────▶ API呼び出し
                          │
                          ▼
API結果 ─────────▶ toast/navigate ─────────▶ フィードバック/遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| order-create-fulfillments.tsx | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/order-create-fulfillments.tsx` | ソース | ページコンポーネント |
| order-create-fulfillment-form.tsx | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-form.tsx` | ソース | フォームコンポーネント |
| order-create-fulfillment-item.tsx | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-item.tsx` | ソース | 商品アイテムコンポーネント |
| constants.ts | `packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/constants.ts` | ソース | 定数・スキーマ定義 |
| orders.tsx | `packages/admin/dashboard/src/hooks/api/orders.tsx` | ソース | API呼び出しフック |
| order-item.ts | `packages/admin/dashboard/src/lib/order-item.ts` | ソース | getFulfillableQuantityなどのユーティリティ |
