# 機能設計書 50-在庫予約管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける在庫予約管理機能の設計を記述する。在庫予約（ReservationItem）は、注文時に特定の在庫アイテムを特定のロケーションで確保するためのエンティティであり、注文と在庫の整合性を保つための重要な機能である。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、注文が確定した際に在庫を確保（予約）し、他の注文で使用されないようにする必要がある。在庫予約管理は、注文ラインアイテムと在庫アイテム・ロケーションを紐付け、予約数量を管理することで、在庫の二重販売を防止し、フルフィルメント処理の確実性を保証する。

**機能の利用シーン**：
- 注文確定時に在庫を予約する場合
- 注文キャンセル時に予約を解除する場合
- 交換注文時に新しい商品の在庫を確保する場合
- 手動で在庫を割り当てる場合

**主要な処理内容**：
1. 予約の作成（createReservationItems）
2. 予約の更新（updateReservationItems）
3. 予約の削除（deleteReservationItems）
4. 予約のソフトデリート（softDeleteReservationItems）
5. 予約の復元（restoreReservationItems）
6. ラインアイテムによる予約削除（deleteReservationItemsByLineItem）

**関連システム・外部連携**：
- 在庫アイテム管理
- 在庫レベル管理（reserved_quantityの自動更新）
- 注文管理（line_item_idによる紐付け）

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 44 | フルフィルメント作成画面 | 補助機能 | 在庫の引当処理 |
| 49 | 交換作成画面 | 補助機能 | 交換品の在庫確保 |
| 52 | 在庫割当画面 | 主機能 | 注文アイテムへの在庫割当 |
| 93 | 在庫詳細画面 | 補助機能 | 予約状況の表示 |
| 100 | 予約一覧画面 | 主機能 | 在庫予約一覧の取得・表示 |
| 101 | 予約作成画面 | 主機能 | 新規予約の作成 |
| 102 | 予約詳細画面 | 主機能 | 予約詳細の表示 |
| 103 | 予約編集画面 | 主機能 | 予約情報の編集 |
| 104 | 予約メタデータ編集画面 | 主機能 | 予約メタデータの編集 |

## 機能種別

CRUD操作、在庫予約

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| inventory_item_id | string | Yes | 在庫アイテムID | 存在チェック |
| location_id | string | Yes | ロケーションID | 在庫レベル存在チェック |
| quantity | BigNumber | Yes | 予約数量 | 利用可能在庫チェック（バックオーダー無効時） |
| line_item_id | string | No | 注文ラインアイテムID | - |
| allow_backorder | boolean | No | バックオーダー許可フラグ | デフォルト: false |
| external_id | string | No | 外部システムID | - |
| description | string | No | 説明 | searchable |
| created_by | string | No | 作成者ID | - |
| metadata | object | No | カスタムメタデータ | JSON形式 |

### 入力データソース

- 管理画面からのフォーム入力
- Admin API経由
- 注文処理ワークフロー経由

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | 予約アイテムID（resitem_xxx形式） |
| inventory_item_id | string | 在庫アイテムID |
| location_id | string | ロケーションID |
| quantity | BigNumber | 予約数量 |
| line_item_id | string | 注文ラインアイテムID |
| allow_backorder | boolean | バックオーダー許可フラグ |
| external_id | string | 外部システムID |
| description | string | 説明 |
| created_by | string | 作成者ID |
| metadata | object | メタデータ |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 入力データの受信
   └─ 予約情報を含む

2. 在庫レベル存在確認
   └─ ensureInventoryLevels()で存在・利用可能在庫チェック

3. 予約の作成
   └─ reservationItemService_.create()

4. 在庫レベルの更新
   └─ reserved_quantityを増加

5. シリアライズとレスポンス返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[入力データ受信]
    B --> C[ensureInventoryLevels]
    C --> D{在庫レベル存在?}
    D -->|No| E[NOT_FOUND エラー]
    D -->|Yes| F{利用可能在庫チェック}
    F -->|不足 & !allow_backorder| G[NOT_ALLOWED エラー]
    F -->|OK or allow_backorder| H[reservationItemService_.create]
    H --> I[adjustments計算]
    I --> J[inventoryLevelService_.update]
    J --> K[reserved_quantity更新]
    K --> L[シリアライズ]
    L --> M[イベント発行]
    M --> N[レスポンス返却]
    E --> O[終了]
    G --> O
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-50-01 | 在庫レベル必須 | 予約作成時にinventory_item_idとlocation_idの組み合わせの在庫レベルが必要 | 作成時 |
| BR-50-02 | 利用可能在庫チェック | allow_backorder=falseの場合、利用可能在庫 >= 予約数量が必要 | 作成・更新時 |
| BR-50-03 | reserved_quantity連動 | 予約の作成/削除/更新時に在庫レベルのreserved_quantityを自動更新 | 作成・更新・削除時 |
| BR-50-04 | allow_backorderデフォルト | allow_backorderのデフォルト値はfalse | 作成時 |

### 計算ロジック

- **予約作成時**: reserved_quantity += quantity
- **予約削除時**: reserved_quantity -= quantity
- **予約更新時**: reserved_quantity += (new_quantity - old_quantity)

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| createReservationItems | reservation_item | INSERT | 新規予約作成 |
| createReservationItems | inventory_level | UPDATE | reserved_quantity増加 |
| updateReservationItems | reservation_item | UPDATE | 予約更新 |
| updateReservationItems | inventory_level | UPDATE | reserved_quantity調整 |
| deleteReservationItems | reservation_item | DELETE | 予約削除 |
| deleteReservationItems | inventory_level | UPDATE | reserved_quantity減少 |

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

#### reservation_item

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動生成（resitem_xxx形式） | プライマリキー |
| INSERT | inventory_item_id | 在庫アイテムID | 外部キー、インデックスあり |
| INSERT | location_id | ロケーションID | インデックスあり |
| INSERT | quantity | 予約数量（BigNumber） | 必須 |
| INSERT | raw_quantity | 予約数量（JSON） | 内部用 |
| INSERT | line_item_id | ラインアイテムID | nullable、インデックスあり |
| INSERT | allow_backorder | バックオーダー許可 | デフォルト: false |
| INSERT | external_id | 外部ID | nullable |
| INSERT | description | 説明 | nullable、searchable |
| INSERT | created_by | 作成者 | nullable |
| INSERT | metadata | メタデータ | nullable、JSON |

### インデックス

| インデックス名 | カラム | 特性 |
|--------------|--------|------|
| IDX_reservation_item_line_item_id | line_item_id | deleted_at IS NULL |
| IDX_reservation_item_location_id | location_id | deleted_at IS NULL |
| IDX_reservation_item_inventory_item_id | inventory_item_id | deleted_at IS NULL |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | 在庫レベルが存在しない | 先に在庫レベルを作成 |
| NOT_ALLOWED | MedusaError | 利用可能在庫が不足（バックオーダー無効時） | 在庫を補充するか、バックオーダーを許可 |
| INVALID_DATA | MedusaError | 更新対象の予約が存在しない | 正しいIDを指定 |

### リトライ仕様

トランザクションレベルでのリトライ対応。

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

- 予約の作成・更新・削除は@InjectTransactionManager()デコレータによりトランザクション管理
- 在庫レベルの更新も同一トランザクション内で実行

## パフォーマンス要件

- line_item_id、location_id、inventory_item_idにインデックス設定済み
- ラインアイテムによる予約削除は効率的に実行可能

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

- 管理者認証必須
- 予約の作成・更新時に在庫可用性チェックを実施

## 備考

- IDプレフィックスは「resitem」
- inventory_itemリレーションはsearchable属性
- 削除・復元時に在庫レベルのreserved_quantityを自動調整

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reservation-item.ts | `packages/modules/inventory/src/models/reservation-item.ts` | エンティティ定義 |
| 1-2 | inventory-level.ts | `packages/modules/inventory/src/models/inventory-level.ts` | 連動するエンティティ |

**読解のコツ**: ReservationItemはinventory_itemへのbelongsToリレーションを持つ。line_item_id、location_id、inventory_item_idにインデックスが設定されており、効率的な検索が可能。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | 予約作成処理 |

**主要処理フロー**:
- **223-255行目**: `createReservationItems()` - 予約作成エントリーポイント
- **257-310行目**: `createReservationItems_()` - 予約作成内部処理
  - **262-275行目**: `ensureInventoryLevels()` - 在庫レベル存在・利用可能在庫チェック
  - **277行目**: `reservationItemService_.create()` - 予約レコード作成
  - **279-305行目**: adjustments計算とreserved_quantity更新

#### Step 3: 予約更新処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | 予約更新処理 |

**主要処理フロー**:
- **553-583行目**: `updateReservationItems()` - 予約更新エントリーポイント
- **585-712行目**: `updateReservationItems_()` - 予約更新内部処理
  - **590-607行目**: 更新対象の予約取得と存在チェック
  - **613-661行目**: adjustments計算（ロケーション変更・数量変更対応）
  - **682-688行目**: `ensureInventoryLevels()` - 利用可能在庫チェック
  - **690行目**: `reservationItemService_.update()` - 予約レコード更新
  - **692-709行目**: reserved_quantity更新

#### Step 4: 予約削除処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | 予約削除処理 |

**主要処理フロー**:
- **714-738行目**: `deleteReservationItems()` - 予約削除（物理削除）
- **740-766行目**: `softDeleteReservationItems()` - 予約ソフトデリート
- **768-794行目**: `restoreReservationItems()` - 予約復元
- **834-864行目**: `deleteReservationItemsByLineItem()` - ラインアイテムによる削除
- **1157-1228行目**: `adjustInventoryLevelsForReservations_()` - 在庫レベル調整処理

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

```
InventoryModuleService
    │
    ├─ createReservationItems() [public]
    │      └─ createReservationItems_() [protected]
    │             ├─ ensureInventoryLevels() [private]
    │             │      └─ validateQuantityAtLocation: true
    │             ├─ reservationItemService_.create()
    │             └─ inventoryLevelService_.update()
    │                    └─ reserved_quantity += quantity
    │
    ├─ updateReservationItems() [public]
    │      └─ updateReservationItems_() [protected]
    │             ├─ reservationItemService_.list()
    │             ├─ adjustments計算
    │             ├─ ensureInventoryLevels() [private]
    │             ├─ reservationItemService_.update()
    │             └─ inventoryLevelService_.update()
    │
    ├─ deleteReservationItems() [public]
    │      └─ deleteReservationItems_() [protected]
    │             ├─ reservationItemService_.list()
    │             ├─ super.deleteReservationItems()
    │             └─ adjustInventoryLevelsForReservationsDeletion()
    │
    ├─ softDeleteReservationItems() [public]
    │      └─ softDeleteReservationItems_() [protected]
    │             ├─ reservationItemService_.list()
    │             ├─ super.softDeleteReservationItems()
    │             └─ adjustInventoryLevelsForReservationsDeletion()
    │
    ├─ restoreReservationItems() [public]
    │      └─ restoreReservationItems_() [protected]
    │             ├─ super.listReservationItems()
    │             ├─ super.restoreReservationItems()
    │             └─ adjustInventoryLevelsForReservationsRestore()
    │
    └─ deleteReservationItemsByLineItem() [public]
           └─ deleteReservationItemsByLineItem_() [protected]
                  ├─ reservationItemService_.list()
                  ├─ reservationItemService_.softDelete()
                  └─ adjustInventoryLevelsForReservationsDeletion()
```

### データフロー図

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

CreateReservationItemInput InventoryModuleService             ReservationItemDTO
         │                          │                                │
         ▼                          ▼                                ▼
    ┌──────────┐           ┌─────────────────┐              ┌──────────────┐
    │ API      │ ────────▶ │ ensureInventory │ ───────────▶ │ JSON Response│
    │ Request  │           │ Levels + create │              │ (serialized) │
    └──────────┘           └─────────────────┘              └──────────────┘
                                   │
                        ┌──────────┴──────────┐
                        ▼                     ▼
                ┌──────────────┐      ┌──────────────┐
                │ reservation_ │      │ inventory_   │
                │ item         │      │ level        │
                │ (INSERT)     │      │ (UPDATE)     │
                └──────────────┘      └──────────────┘

[予約削除フロー]

reservation_ids            deleteReservationItems            void
         │                          │                          │
         ▼                          ▼                          ▼
    ┌──────────┐           ┌─────────────────┐          ┌──────────┐
    │ 削除     │ ────────▶ │ adjustInventory │ ───────▶ │ 完了     │
    │ リクエスト│           │ LevelsFor...    │          │          │
    └──────────┘           └─────────────────┘          └──────────┘
                                   │
                        ┌──────────┴──────────┐
                        ▼                     ▼
                ┌──────────────┐      ┌──────────────┐
                │ reservation_ │      │ reserved_    │
                │ item削除     │      │ quantity     │
                │              │      │ -= quantity  │
                └──────────────┘      └──────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | ソース | モジュールサービス本体 |
| reservation-item.ts | `packages/modules/inventory/src/models/reservation-item.ts` | ソース | 予約アイテムエンティティ |
| inventory-level.ts | `packages/modules/inventory/src/models/inventory-level.ts` | ソース | 在庫レベルエンティティ |
| inventory-item.ts | `packages/modules/inventory/src/models/inventory-item.ts` | ソース | 親エンティティ |
