# 機能設計書 45-フルフィルメント処理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおけるフルフィルメント処理機能の設計を記述する。フルフィルメントは、注文に対する出荷処理を管理するエンティティであり、配送プロバイダーとの連携、ラベル発行、出荷・配達状態の追跡を担当する。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、注文された商品を顧客に届けるための出荷プロセスを管理する必要がある。フルフィルメント処理は、在庫ロケーションからの出荷、配送プロバイダーへの連携、配送ラベルの発行、出荷・配達状態の更新を一元管理し、物流業務を効率化する。

**機能の利用シーン**：
- 注文に対して出荷処理を開始する場合
- 配送プロバイダーにフルフィルメントデータを送信する場合
- 配送ラベルを発行・更新する場合
- 出荷・配達状態を更新する場合
- フルフィルメントをキャンセルする場合
- 返品フルフィルメントを作成する場合

**主要な処理内容**：
1. フルフィルメントの作成（配送プロバイダー連携を含む）
2. 返品フルフィルメントの作成
3. フルフィルメントの更新（ラベル情報等）
4. フルフィルメントのキャンセル（プロバイダー連携）
5. フルフィルメントの削除（キャンセル済みの場合のみ）
6. フルフィルメントの取得・一覧表示

**関連システム・外部連携**：
- 配送プロバイダー（FulfillmentProvider）との連携
  - createFulfillment: プロバイダーにフルフィルメント作成リクエスト
  - createReturn: プロバイダーに返品フルフィルメント作成リクエスト
  - cancelFulfillment: プロバイダーにキャンセルリクエスト
- 注文モジュールとの連携
- 在庫モジュールとの連携（在庫予約）

**権限による制御**：管理画面からの操作は管理者権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 43 | 注文詳細画面 | 遷移先機能 | フルフィルメント作成画面への遷移 |
| 44 | フルフィルメント作成画面 | 主機能 | 注文のフルフィルメント作成 |
| 45 | 出荷作成画面 | 主機能 | 出荷情報の作成 |

## 機能種別

処理実行、外部連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| location_id | string | Yes | 出荷元ロケーションID | - |
| provider_id | string | Yes | 配送プロバイダーID | - |
| shipping_option_id | string | No | 配送オプションID | - |
| items | array | Yes | 出荷アイテムの配列 | - |
| items[].title | string | Yes | アイテム名 | - |
| items[].quantity | number | Yes | 数量 | 正の整数 |
| items[].sku | string | No | SKU | - |
| items[].barcode | string | No | バーコード | - |
| items[].line_item_id | string | No | 注文明細ID | - |
| items[].inventory_item_id | string | No | 在庫アイテムID | - |
| order | object | No | 注文情報（プロバイダー連携用） | - |
| data | object | No | プロバイダー固有データ | JSON形式 |
| labels | array | No | 配送ラベル情報 | - |
| delivery_address | object | No | 配送先住所 | - |
| metadata | object | No | カスタムメタデータ | JSON形式 |

### 入力データソース

- 管理画面からのフォーム入力
- Admin API（POST /admin/fulfillments）
- ワークフロー（core-flows）からの呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | フルフィルメントID（ful_xxx形式） |
| location_id | string | 出荷元ロケーションID |
| provider_id | string | 配送プロバイダーID |
| shipping_option_id | string | 配送オプションID |
| items | array | 出荷アイテムの配列 |
| labels | array | 配送ラベルの配列 |
| packed_at | datetime | 梱包日時 |
| shipped_at | datetime | 出荷日時 |
| delivered_at | datetime | 配達日時 |
| canceled_at | datetime | キャンセル日時 |
| requires_shipping | boolean | 出荷が必要かどうか |
| data | object | プロバイダー固有データ |
| delivery_address | object | 配送先住所 |
| metadata | object | メタデータ |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |

### 出力先

- API Response（JSON形式）
- DBテーブル：fulfillment, fulfillment_item, fulfillment_label, fulfillment_address

## 処理フロー

### 処理シーケンス

```
1. フルフィルメントデータの受信
   └─ 注文情報、アイテム情報を含む

2. フルフィルメントレコードの作成
   └─ fulfillmentService_.create()でDB登録

3. 配送プロバイダーへの連携
   └─ fulfillmentProviderService_.createFulfillment()
   └─ プロバイダーからラベル情報等を取得

4. フルフィルメントレコードの更新
   └─ プロバイダーからの結果（data, labels）を反映

5. エラー時のロールバック
   └─ プロバイダー連携失敗時はフルフィルメントを削除

6. レスポンスの生成とイベント発行
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[フルフィルメントデータ受信]
    B --> C[DB登録]
    C --> D[配送プロバイダー連携]
    D --> E{連携成功?}
    E -->|Yes| F[プロバイダー結果でDB更新]
    E -->|No| G[フルフィルメント削除]
    G --> H[エラー返却]
    F --> I[シリアライズ]
    I --> J[イベント発行]
    J --> K[レスポンス返却]
    H --> L[終了]
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | プロバイダー連携必須 | フルフィルメント作成時は配送プロバイダーへの連携が必要 | 作成時 |
| BR-45-02 | 連携失敗時ロールバック | プロバイダー連携失敗時はフルフィルメントを削除 | 作成時 |
| BR-45-03 | キャンセル前提削除 | 削除はキャンセル済みのフルフィルメントのみ可能 | 削除時 |
| BR-45-04 | 出荷済みキャンセル不可 | shipped_atが設定されている場合はキャンセル不可 | キャンセル時 |
| BR-45-05 | 配達済みキャンセル不可 | delivered_atが設定されている場合はキャンセル不可 | キャンセル時 |
| BR-45-06 | カスケード削除 | フルフィルメント削除時、アイテム・ラベル・住所も削除 | 削除時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| createFulfillment | fulfillment | INSERT | 新規フルフィルメント作成 |
| createFulfillment | fulfillment_item | INSERT | アイテム作成 |
| createFulfillment | fulfillment_address | INSERT | 配送先住所作成 |
| createFulfillment | fulfillment | UPDATE | プロバイダー結果反映 |
| createFulfillment | fulfillment_label | INSERT | ラベル作成 |
| updateFulfillment | fulfillment | UPDATE | フルフィルメント更新 |
| updateFulfillment | fulfillment_label | INSERT/UPDATE/DELETE | ラベル更新 |
| cancelFulfillment | fulfillment | UPDATE | canceled_at設定 |
| deleteFulfillment | fulfillment | DELETE | 削除 |
| deleteFulfillment | fulfillment_item | DELETE | カスケード削除 |
| deleteFulfillment | fulfillment_label | DELETE | カスケード削除 |
| deleteFulfillment | fulfillment_address | DELETE | カスケード削除 |

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

#### fulfillment

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動生成（ful_xxx形式） | プライマリキー |
| INSERT | location_id | 入力値 | インデックスあり |
| INSERT | provider_id | 入力値 | 外部キー |
| INSERT | shipping_option_id | 入力値 | 外部キー（nullable） |
| INSERT | requires_shipping | 入力値 | デフォルト: true |
| UPDATE | data | プロバイダー結果 | JSON |
| UPDATE | shipped_at | 出荷日時 | - |
| UPDATE | delivered_at | 配達日時 | - |
| UPDATE | canceled_at | キャンセル日時 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| INVALID_DATA | MedusaError | キャンセル済みでないフルフィルメントを削除しようとした | 先にキャンセル処理を実行 |
| INVALID_DATA | MedusaError | 出荷済みフルフィルメントをキャンセルしようとした | キャンセル不可 |
| INVALID_DATA | MedusaError | 配達済みフルフィルメントをキャンセルしようとした | キャンセル不可 |
| PROVIDER_ERROR | Error | 配送プロバイダーとの連携失敗 | プロバイダー設定を確認 |

### リトライ仕様

- プロバイダー連携失敗時はフルフィルメントが削除されるため、再度作成処理が必要

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

- フルフィルメント作成とプロバイダー連携は同一トランザクションではない
- プロバイダー連携失敗時は明示的にフルフィルメントを削除

## パフォーマンス要件

- プロバイダー連携のため、通常のCRUDより処理時間が長くなる可能性あり

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

- 配送先住所は個人情報を含むため適切に保護
- 管理者認証必須

## 備考

- IDプレフィックスは「ful」
- フルフィルメントアイテムのプレフィックスは別途定義
- ラベル情報はプロバイダーから取得

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fulfillment.ts | `packages/modules/fulfillment/src/models/fulfillment.ts` | エンティティ定義、リレーション |
| 1-2 | fulfillment-item.ts | `packages/modules/fulfillment/src/models/fulfillment-item.ts` | アイテムエンティティ |
| 1-3 | fulfillment-label.ts | `packages/modules/fulfillment/src/models/fulfillment-label.ts` | ラベルエンティティ |
| 1-4 | address.ts | `packages/modules/fulfillment/src/models/address.ts` | 配送先住所エンティティ |

**読解のコツ**: Fulfillmentはitems, labels, delivery_addressへのリレーションを持ち、カスケード削除が設定されている（52-54行目）。shipped_at, delivered_at, canceled_atの各タイムスタンプで状態を管理。

#### Step 2: 作成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fulfillment-module-service.ts | `packages/modules/fulfillment/src/services/fulfillment-module-service.ts` | createFulfillment |

**主要処理フロー**:
1. **600-645行目**: `createFulfillment()` - メインエントリーポイント
   - **606行目**: orderを入力から分離（プロバイダー連携用）
   - **608-611行目**: fulfillmentService_.create()でDB登録
   - **621-628行目**: fulfillmentProviderService_.createFulfillment()でプロバイダー連携
   - **629-636行目**: プロバイダー結果（data, labels）でDB更新
   - **637-640行目**: エラー時にフルフィルメント削除

#### Step 3: キャンセル・削除処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fulfillment-module-service.ts | `packages/modules/fulfillment/src/services/fulfillment-module-service.ts` | cancelFulfillment, deleteFulfillment |

**主要処理フロー**:
- **647-667行目**: `deleteFulfillment()` - canceled_atチェック後に削除
- **1885-1926行目**: `cancelFulfillment()` - キャンセル可否チェック、プロバイダー連携、canceled_at設定
- **2077-2095行目**: `canCancelFulfillmentOrThrow()` - shipped_at/delivered_atチェック

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

```
FulfillmentModuleService
    │
    ├─ createFulfillment() [public]
    │      ├─ fulfillmentService_.create() - DB登録
    │      ├─ fulfillmentProviderService_.createFulfillment() - プロバイダー連携
    │      ├─ fulfillmentService_.update() - 結果反映
    │      └─ fulfillmentService_.delete() - エラー時ロールバック
    │
    ├─ createReturnFulfillment() [public]
    │      ├─ fulfillmentService_.create()
    │      ├─ shippingOptionService_.retrieve()
    │      ├─ fulfillmentProviderService_.createReturn()
    │      └─ fulfillmentService_.update()
    │
    ├─ updateFulfillment() [public]
    │      └─ updateFulfillment_() [protected]
    │             └─ fulfillmentService_.update()
    │
    ├─ cancelFulfillment() [public]
    │      ├─ canCancelFulfillmentOrThrow() [static]
    │      ├─ fulfillmentProviderService_.cancelFulfillment()
    │      └─ fulfillmentService_.update() - canceled_at設定
    │
    └─ deleteFulfillment() [public]
           ├─ fulfillmentService_.retrieve() - canceled_atチェック
           └─ fulfillmentService_.delete()
```

### データフロー図

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

CreateFulfillmentDTO        FulfillmentModuleService              FulfillmentDTO
         │                           │                                  │
         ▼                           ▼                                  ▼
    ┌──────────┐           ┌──────────────────┐               ┌──────────────┐
    │ API      │ ────────▶ │ createFulfillment│ ────────────▶ │ JSON Response│
    │ Request  │           │                  │               │ (serialized) │
    └──────────┘           └──────────────────┘               └──────────────┘
                                    │
                    ┌───────────────┼───────────────┐
                    ▼               ▼               ▼
             ┌───────────┐  ┌───────────────┐  ┌───────────┐
             │fulfillment│  │ FulfillmentPro│  │fulfillment│
             │ (DB)      │  │ viderService  │  │ _label    │
             └───────────┘  └───────────────┘  └───────────┘
                                    │
                                    ▼
                           ┌───────────────┐
                           │ 外部配送      │
                           │ プロバイダー  │
                           └───────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fulfillment-module-service.ts | `packages/modules/fulfillment/src/services/fulfillment-module-service.ts` | ソース | モジュールサービス本体 |
| fulfillment-provider.ts | `packages/modules/fulfillment/src/services/fulfillment-provider.ts` | ソース | プロバイダーサービス |
| fulfillment.ts | `packages/modules/fulfillment/src/models/fulfillment.ts` | ソース | フルフィルメントエンティティ |
| fulfillment-item.ts | `packages/modules/fulfillment/src/models/fulfillment-item.ts` | ソース | アイテムエンティティ |
| fulfillment-label.ts | `packages/modules/fulfillment/src/models/fulfillment-label.ts` | ソース | ラベルエンティティ |
| address.ts | `packages/modules/fulfillment/src/models/address.ts` | ソース | 住所エンティティ |
