# 機能設計書 46-配送プロバイダー管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける配送プロバイダー管理機能の設計を記述する。配送プロバイダーは、外部の配送サービス（ヤマト運輸、佐川急便、FedEx、UPSなど）との連携を抽象化し、フルフィルメント処理における配送機能を提供するためのプラグイン機構である。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、複数の配送業者と連携する必要がある。配送プロバイダー管理は、各配送業者のAPIとの連携を抽象化し、フルフィルメント作成、キャンセル、配送料金計算、返品フルフィルメント作成などの機能を統一的なインターフェースで提供する。これにより、新規配送業者の追加が容易になる。

**機能の利用シーン**：
- 配送プロバイダーの有効/無効を設定する場合
- 配送オプションの料金を動的に計算する場合
- フルフィルメント作成時にプロバイダーにリクエストを送信する場合
- プロバイダーが提供する配送オプションを取得する場合

**主要な処理内容**：
1. 配送プロバイダーの登録・取得・一覧表示
2. プロバイダーが提供する配送オプション取得（getFulfillmentOptions）
3. フルフィルメントデータの検証（validateFulfillmentData）
4. フルフィルメントの作成（createFulfillment）
5. フルフィルメントのキャンセル（cancelFulfillment）
6. 返品フルフィルメントの作成（createReturn）
7. 配送料金の計算（calculatePrice）
8. 計算可否の確認（canCalculate）

**関連システム・外部連携**：
- 外部配送業者API（プロバイダー実装により異なる）
- フルフィルメントモジュール
- 配送オプション

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 135 | フルフィルメントプロバイダー設定画面 | 主機能 | フルフィルメントプロバイダーの設定 |
| 139 | 配送オプション作成画面 | API連携 | 配送プロバイダー情報の取得 |

## 機能種別

外部連携、プラグイン管理

## 入力仕様

### 入力パラメータ（プロバイダー登録）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | プロバイダーID | プロバイダークラスのidentifierから生成 |
| is_enabled | boolean | No | 有効/無効フラグ | デフォルト: true |

### プロバイダーインターフェース

| メソッド | 引数 | 戻り値 | 説明 |
|---------|------|--------|------|
| getFulfillmentOptions | なし | FulfillmentOption[] | 提供する配送オプション一覧 |
| validateFulfillmentData | optionData, data, context | Record<string, unknown> | フルフィルメントデータの検証 |
| validateOption | data | boolean | 配送オプションの有効性検証 |
| canCalculate | data | boolean | 料金計算可否 |
| calculatePrice | optionData, data, context | CalculatedPrice | 料金計算 |
| createFulfillment | data, items, order, fulfillment | CreateFulfillmentResult | フルフィルメント作成 |
| cancelFulfillment | fulfillment | any | フルフィルメントキャンセル |
| createReturnFulfillment | fulfillment | CreateFulfillmentResult | 返品フルフィルメント作成 |

### 入力データソース

- プロバイダープラグインの登録（medusa-config.js）
- 管理画面からの有効/無効設定
- フルフィルメントサービスからの呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | プロバイダーID（serpro_xxx形式） |
| is_enabled | boolean | 有効/無効フラグ |

### 出力先

- API Response（JSON形式）
- DBテーブル：fulfillment_provider

## 処理フロー

### 処理シーケンス

```
1. プロバイダー登録（起動時）
   └─ DIコンテナにfp_{providerId}として登録

2. プロバイダー取得
   └─ retrieveProviderRegistration()でコンテナから取得
   └─ 未登録の場合はエラー

3. プロバイダーメソッド呼び出し
   └─ フルフィルメントサービス経由で各メソッドを実行
   └─ プロバイダー実装に処理を委譲
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[プロバイダーID取得]
    B --> C{コンテナに登録済み?}
    C -->|Yes| D[プロバイダー実装取得]
    C -->|No| E[エラー返却]
    D --> F[メソッド呼び出し]
    F --> G[プロバイダー処理実行]
    G --> H[結果返却]
    E --> I[終了]
    H --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | プロバイダー識別子必須 | プロバイダークラスにはstatic identifierが必須 | 登録時 |
| BR-46-02 | コンテナ登録形式 | DIコンテナにfp_{providerId}形式で登録 | 起動時 |
| BR-46-03 | 未登録エラー | 登録されていないプロバイダーIDを指定した場合エラー | 取得時 |
| BR-46-04 | 計算可能チェック | calculated価格タイプの場合canCalculateで確認必須 | 料金計算前 |

### 計算ロジック

- **料金計算**：`calculatePrice()`メソッドでプロバイダー固有のロジックを実行
- 結果は`CalculatedShippingOptionPrice`形式で返却

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 登録 | fulfillment_provider | INSERT | プロバイダー登録 |
| 取得 | fulfillment_provider | SELECT | プロバイダー情報取得 |
| 更新 | fulfillment_provider | UPDATE | is_enabled更新 |

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

#### fulfillment_provider

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | プロバイダーID（serpro_xxx形式） | プライマリキー |
| INSERT | is_enabled | true/false | デフォルト: true |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| INVALID_ARGUMENT | MedusaError | プロバイダーにidentifierがない | identifierを定義 |
| ResolutionError | Error | プロバイダーがコンテナに未登録 | medusa-config.jsで正しく登録 |
| PROVIDER_ERROR | Error | プロバイダー処理中のエラー | プロバイダーログを確認 |

### リトライ仕様

プロバイダー固有のリトライ処理は各プロバイダー実装に委譲。

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

- DBへのプロバイダー情報保存は通常のトランザクション
- 外部API連携はプロバイダー実装依存

## パフォーマンス要件

- プロバイダーは起動時にDIコンテナに登録されるため取得は高速
- 外部API連携のレスポンス時間はプロバイダー依存

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

- プロバイダーのAPIキー等はmedusa-config.jsまたは環境変数で管理
- 外部APIとの通信はHTTPS必須

## 備考

- プロバイダーIDの形式は「{identifier}_{optionName}」
- IDプレフィックスは「serpro」
- カスタムプロバイダーの実装はIFulfillmentProviderインターフェースに準拠

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fulfillment-provider.ts | `packages/modules/fulfillment/src/models/fulfillment-provider.ts` | エンティティ定義 |

**読解のコツ**: FulfillmentProviderエンティティは非常にシンプルで、idとis_enabledのみ。実際のプロバイダーロジックはDIコンテナに登録されるクラスで実装される。

#### Step 2: プロバイダーサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fulfillment-provider.ts | `packages/modules/fulfillment/src/services/fulfillment-provider.ts` | プロバイダーサービス |

**主要処理フロー**:
1. **46-57行目**: `getRegistrationIdentifier()` - プロバイダー登録ID生成
2. **59-81行目**: `retrieveProviderRegistration()` - コンテナからプロバイダー取得
3. **83-96行目**: `listFulfillmentOptions()` - 複数プロバイダーの配送オプション取得
4. **98-103行目**: `getFulfillmentOptions()` - 単一プロバイダーの配送オプション取得
5. **105-113行目**: `validateFulfillmentData()` - フルフィルメントデータ検証
6. **120-123行目**: `canCalculate()` - 料金計算可否確認
7. **125-133行目**: `calculatePrice()` - 料金計算
8. **135-144行目**: `createFulfillment()` - フルフィルメント作成
9. **146-152行目**: `cancelFulfillment()` - フルフィルメントキャンセル
10. **154-158行目**: `createReturn()` - 返品フルフィルメント作成

#### Step 3: モジュールサービスからの呼び出しを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fulfillment-module-service.ts | `packages/modules/fulfillment/src/services/fulfillment-module-service.ts` | プロバイダー連携箇所 |

**主要処理フロー**:
- **621-628行目**: `createFulfillment()`からのプロバイダー呼び出し
- **690-698行目**: `createReturnFulfillment()`からのプロバイダー呼び出し
- **1904-1908行目**: `cancelFulfillment()`からのプロバイダー呼び出し
- **1928-1934行目**: `retrieveFulfillmentOptions()` - プロバイダーの配送オプション取得
- **2003-2016行目**: `calculateShippingOptionsPrices()` - 料金計算

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

```
FulfillmentModuleService
    │
    └─ fulfillmentProviderService_
           │
           ├─ getRegistrationIdentifier() [static]
           │      └─ プロバイダークラスからID生成
           │
           ├─ retrieveProviderRegistration() [protected]
           │      └─ __container__[`fp_${providerId}`]
           │
           ├─ getFulfillmentOptions()
           │      └─ provider.getFulfillmentOptions()
           │
           ├─ validateFulfillmentData()
           │      └─ provider.validateFulfillmentData()
           │
           ├─ canCalculate()
           │      └─ provider.canCalculate()
           │
           ├─ calculatePrice()
           │      └─ provider.calculatePrice()
           │
           ├─ createFulfillment()
           │      └─ provider.createFulfillment()
           │
           ├─ cancelFulfillment()
           │      └─ provider.cancelFulfillment()
           │
           └─ createReturn()
                  └─ provider.createReturnFulfillment()
```

### データフロー図

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

プロバイダーID             FulfillmentProviderService           プロバイダー結果
         │                          │                                  │
         ▼                          ▼                                  ▼
    ┌──────────┐           ┌──────────────────┐               ┌──────────────┐
    │ Module   │ ────────▶ │ retrieveProvider │ ────────────▶ │ プロバイダー │
    │ Service  │           │ Registration     │               │ メソッド結果 │
    └──────────┘           └──────────────────┘               └──────────────┘
                                    │
                                    ▼
                           ┌───────────────────┐
                           │ DIコンテナ        │
                           │ fp_{providerId}   │
                           └───────────────────┘
                                    │
                                    ▼
                           ┌───────────────────┐
                           │ IFulfillment      │
                           │ Provider実装      │
                           └───────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fulfillment-provider.ts | `packages/modules/fulfillment/src/services/fulfillment-provider.ts` | ソース | プロバイダーサービス |
| fulfillment-provider.ts | `packages/modules/fulfillment/src/models/fulfillment-provider.ts` | ソース | プロバイダーエンティティ |
| fulfillment-module-service.ts | `packages/modules/fulfillment/src/services/fulfillment-module-service.ts` | ソース | 呼び出し元サービス |
