# 画面設計書 96-在庫ロケーション管理画面

## 概要

本ドキュメントは、Medusa Admin Dashboardの在庫ロケーション管理画面の設計仕様を定義するものです。

### 本画面の処理概要

在庫ロケーション管理画面は、在庫アイテムが保管されるロケーション（倉庫・店舗など）の追加・削除を管理するためのドロワー形式の画面です。

**業務上の目的・背景**：在庫アイテムは複数のロケーション（倉庫、店舗、外部倉庫など）に分散して保管されることがあります。本画面では、特定の在庫アイテムがどのロケーションで管理されるかを設定できます。ロケーションを追加すると、そのロケーションでの在庫レベル（在庫数量）の管理が可能になります。

**画面へのアクセス方法**：在庫詳細画面のロケーション別在庫セクションから「Manage Locations」ボタンをクリックすることでドロワー形式で表示されます。URL `/inventory/{id}/locations` に直接アクセスすることも可能です。

**主要な操作・処理内容**：
1. 現在の在庫アイテム情報（タイトル、SKU）の表示
2. ロケーション一覧の表示（検索機能付き）
3. ロケーションの選択・選択解除
4. 選択状態の保存（ロケーションの追加・削除）

**画面遷移**：
- 遷移元：在庫詳細画面
- 遷移先：保存成功時は在庫詳細画面に戻る（ドロワークローズ）

**権限による表示制御**：認証済みユーザーであれば全機能を利用可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | 在庫レベル管理 | 主機能 | 在庫のロケーション設定 |
| 79 | 在庫ロケーションCRUD | API連携 | ロケーション一覧の取得 |

## 画面種別

編集（モーダル形式 / ドロワー）

## URL/ルーティング

`/inventory/{id}/locations`

## 入出力項目

### 入力項目

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| 検索キーワード | searchQuery | string | - | ロケーション名での絞り込み |
| ロケーション選択 | selectedLocationIds | Set<string> | - | 選択されたロケーションID群 |

## 表示項目

| 項目名 | 項目ID | 型 | 説明 |
|--------|--------|-----|------|
| タイトル | item.title | string | 在庫アイテムのタイトル |
| SKU | item.sku | string | 在庫管理単位コード |
| 選択数/総数 | selectedCount/totalCount | string | 「X of Y selected」形式 |
| ロケーション名 | location.name | string | ロケーションの名前 |
| チェックボックス | selected | boolean | ロケーション選択状態 |

## イベント仕様

### 1-Saveボタン押下

選択状態の変更に基づいて、ロケーションレベルの作成・削除を実行します。

**処理フロー**:
1. 新規選択されたロケーションを特定（toCreate）
2. 選択解除されたロケーションを特定（toDelete）
3. `useBatchInventoryItemLocationLevels` で一括作成・削除を実行
4. 成功時、トースト通知（inventory.toast.updateLocations）を表示しドロワーをクローズ
5. エラー時、エラーメッセージをトースト表示

### 2-Cancelボタン押下

入力内容を破棄してドロワーをクローズします。

### 3-検索入力

入力されたキーワードでロケーション一覧をフィルタリングします。

### 4-ロケーション選択/選択解除

チェックボックスの状態を切り替え、選択されたロケーションIDセットを更新します。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 初期表示 | inventory_item | SELECT | 在庫アイテム情報の取得 |
| 初期表示 | stock_location | SELECT | ロケーション一覧の取得 |
| Save押下 | inventory_level | INSERT | 新規ロケーションレベルの作成 |
| Save押下 | inventory_level | DELETE | 選択解除されたロケーションレベルの削除 |

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

#### inventory_level

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | inventory_item_id | 対象在庫アイテムのID | - |
| INSERT | location_id | 選択されたロケーションID | - |
| DELETE | id | 選択解除されたレベルのID | - |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| inventory.toast.updateLocations | 成功 | ロケーションが正常に更新されました | 更新成功時 |
| - | エラー | エラーメッセージ（API エラー内容） | API 呼び出しエラー時 |

## 例外処理

| 例外条件 | 対応 | 画面表示 |
|---------|------|----------|
| 在庫アイテムが存在しない | エラーをスロー | エラー画面を表示 |
| ロケーション取得エラー | エラーをスロー | エラー画面を表示 |
| APIエラー | トースト通知 | エラーメッセージを表示 |

## 備考

- RouteDrawer形式で実装
- InfiniteListコンポーネントで無限スクロール対応（ページサイズ: 20）
- 検索はロケーション名でのフィルタリング
- 既存の在庫レベルがあるロケーションは初期選択状態

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | inventory-level.ts | `packages/modules/inventory/src/models/inventory-level.ts` | InventoryLevelエンティティ。inventory_item_idとlocation_idの関係を確認 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | manage-locations-drawer.tsx | `packages/admin/dashboard/src/routes/inventory/inventory-detail/components/manage-locations/manage-locations-drawer.tsx` | ドロワーコンポーネント |
| 2-2 | manage-locations-form.tsx | `packages/admin/dashboard/src/routes/inventory/inventory-detail/components/manage-locations/components/manage-locations-form.tsx` | フォームコンポーネント |

**主要処理フロー**:
1. **26-29行目（form）**: 既存のロケーションレベルからlocation_idのセットを作成
2. **33-36行目（form）**: selectedLocationIdsステートで選択状態を管理
3. **40-49行目（form）**: handleLocationSelectで選択状態を更新
4. **54-84行目（form）**: handleSubmitで作成・削除を実行
5. **132-165行目（form）**: InfiniteListでロケーション一覧を表示

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

```
ManageLocationsDrawer (manage-locations-drawer.tsx)
    │
    ├─ useInventoryItem (inventory.tsx)
    │      └─ sdk.admin.inventoryItem.retrieve()
    │
    ├─ useStockLocations (stock-locations.tsx)
    │      └─ sdk.admin.stockLocation.list()
    │
    └─ ManageLocationsForm (manage-locations-form.tsx)
           │
           ├─ InfiniteList
           │      └─ sdk.admin.stockLocation.list()
           │
           └─ useBatchInventoryItemLocationLevels (inventory.tsx)
                  └─ sdk.admin.inventoryItem.batchInventoryItemLocationLevels()
```

### データフロー図

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

検索キーワード ──────────▶ InfiniteList ──▶ ロケーション一覧表示
                                │
ロケーション選択 ──────────┐   │
                          │   │
                          ▼   ▼
                   selectedLocationIds
                          │
                          ▼
          差分計算（toCreate / toDelete）
                          │
                          ▼
    useBatchInventoryItemLocationLevels ──▶ inventory_level CREATE/DELETE
                          │
                          ▼
                    handleSuccess ──▶ ドロワークローズ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| manage-locations-drawer.tsx | `packages/admin/dashboard/src/routes/inventory/inventory-detail/components/manage-locations/manage-locations-drawer.tsx` | ソース | ドロワーコンポーネント |
| manage-locations-form.tsx | `packages/admin/dashboard/src/routes/inventory/inventory-detail/components/manage-locations/components/manage-locations-form.tsx` | ソース | フォームコンポーネント |
| location-item.tsx | `packages/admin/dashboard/src/routes/inventory/inventory-detail/components/manage-locations/components/location-item.tsx` | ソース | ロケーション項目コンポーネント |
| location-search-input.tsx | `packages/admin/dashboard/src/routes/inventory/inventory-detail/components/manage-locations/components/location-search-input.tsx` | ソース | 検索入力コンポーネント |
| inventory.tsx | `packages/admin/dashboard/src/hooks/api/inventory.tsx` | ソース | API フック |
