# 画面設計書 76-価格追加画面

## 概要

本ドキュメントは、Medusa Admin Dashboardにおける「価格追加画面」の画面設計書です。価格表に新規商品と価格を追加するためのウィザード形式のモーダル画面について記述します。

### 本画面の処理概要

この画面では、既存の価格表に対して2ステップのウィザード形式で新規商品と価格を追加します。対象商品選択後、選択した商品のバリアントに対して価格を設定します。

**業務上の目的・背景**：価格表作成後に追加で商品を含めたい場合や、新商品が入荷した際に既存の価格表に追加する必要がある場合に使用します。ウィザード形式により、商品選択と価格設定を明確に分離し、操作の誤りを防止しています。

**画面へのアクセス方法**：価格表詳細画面のProducts Sectionの「Add Products」ボタンをクリック、またはURL `/price-lists/{id}/products/add` に直接アクセスすることで表示されます。

**主要な操作・処理内容**：
1. Step 1（Products）：価格表に含める商品の選択（既存商品は除外）
2. Step 2（Prices）：選択した商品の各バリアントに対する価格設定
3. 価格の一括登録

**画面遷移**：
- 遷移元：価格表詳細画面
- 遷移先：保存成功時・キャンセル時に価格表詳細画面に戻る

**権限による表示制御**：認証済みユーザーのみアクセス可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 53 | 価格リスト管理 | 主機能 | 価格表への商品・価格追加 |

## 画面種別

モーダル形式（RouteFocusModal）/ ウィザード形式

## URL/ルーティング

`/price-lists/:id/products/add`

## 入出力項目

### パスパラメータ（入力）

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| id | string | Yes | 価格表のID |

### Step 1: Products（商品選択）

| 項目名 | フィールド名 | 型 | 必須 | バリデーション | 説明 |
|--------|-------------|-----|------|---------------|------|
| 商品ID配列 | product_ids | array | Yes | 1件以上 | 価格設定対象の商品 |

### Step 2: Prices（価格設定）

| 項目名 | フィールド名 | 型 | 必須 | バリデーション | 説明 |
|--------|-------------|-----|------|---------------|------|
| 商品別価格 | products | object | Yes | - | 商品・バリアント別の価格設定 |
| 通貨別価格 | currency_prices | object | No | 数値 | 通貨コードごとの価格 |
| リージョン別価格 | region_prices | object | No | 数値 | リージョンIDごとの価格 |

## 表示項目

### ヘッダー部

| 項目名 | 説明 |
|--------|------|
| ProgressTabs | 2ステップのプログレスインジケータ（Products/Prices） |

### Step 1: Products フォーム

| 項目名 | コンポーネント | 説明 |
|--------|--------------|------|
| 商品選択テーブル | DataTable | 既存商品を除外した商品一覧から選択 |

### Step 2: Prices フォーム

| 項目名 | コンポーネント | 説明 |
|--------|--------------|------|
| 価格入力グリッド | DataGrid | バリアント×通貨/リージョンのマトリクス |

## イベント仕様

### 1-タブ切り替え

ProgressTabsのタブをクリックすると、該当ステップに移動します。次のステップへの移動時は現在のステップのバリデーションが実行されます。

### 2-商品選択

商品一覧テーブルで価格設定対象の商品を選択します。既に価格表に含まれている商品は表示されません。

### 3-Continueボタン押下（Step 1）

選択した商品が1件以上あることを確認し、次のステップに進みます。

### 4-価格入力

DataGridで各バリアント・通貨/リージョンの組み合わせに価格を入力します。

### 5-Saveボタン押下（Step 2）

`useBatchPriceListPrices`フックを使用して、選択した商品の価格を一括登録します。

### 6-Cancelボタン押下

モーダルを閉じ、価格表詳細画面に戻ります。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | price_list | SELECT | 価格表詳細の取得 |
| 画面表示 | product | SELECT | 商品一覧の取得 |
| Save押下 | price | INSERT | 価格レコードの作成（複数） |

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

#### price（Save時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | amount | 入力された価格（数値変換済み） | 必須 |
| INSERT | currency_code | 通貨コード | 必須 |
| INSERT | variant_id | バリアントID | 必須 |
| INSERT | price_list_id | 価格表ID | 必須 |
| INSERT | rules | リージョン指定時は `{ region_id: xxx }` | 任意 |

## メッセージ仕様

| 種別 | 条件 | メッセージ |
|------|------|-----------|
| 成功 | 価格追加成功時 | Products successfully added to price list. |
| エラー | バリデーション失敗時 | 各フィールドにエラーメッセージ表示 |
| エラー | API呼び出し失敗時 | エラーメッセージをトースト表示 |

## 例外処理

| 状態 | 処理 |
|------|------|
| 価格表が存在しない場合 | エラーをスローし、エラーバウンダリーで捕捉 |
| データ取得中 | フォームを表示しない（ready判定） |
| バリデーションエラー | フォームフィールドにエラー表示、ステップ進行をブロック |
| API エラー発生時 | エラーメッセージをトースト表示 |

## 備考

- 2ステップのウィザード形式（Products → Prices）
- 既に価格表に含まれている商品は選択不可
- 価格入力はDataGridコンポーネントを使用したスプレッドシート風UI
- usePriceListCurrencyDataで通貨・リージョン・価格設定を事前取得

---

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

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

### 推奨読解順序

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

ページコンポーネントとデータ取得処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | price-list-prices-add.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/price-list-prices-add.tsx` | RouteFocusModal構成、データ取得 |

**主要処理フロー**:
1. **8行目**: useParamsでURLからid取得
2. **10-13行目**: usePriceListで価格表データ取得（価格・バリアント情報含む）
3. **14-15行目**: usePriceListCurrencyDataで通貨・リージョンデータ取得
4. **17行目**: ready判定

#### Step 2: メインフォームを理解する

ウィザード全体の制御ロジックを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | price-list-prices-add-form.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/price-list-prices-add-form.tsx` | ウィザードステップ管理、API呼び出し |

**主要処理フロー**:
- **32-45行目**: Tab列挙型とTabState定義
- **59-65行目**: useFormでフォーム初期化
- **67行目**: useBatchPriceListPricesで価格バッチ登録
- **69-86行目**: handleSubmit - 価格抽出とAPI呼び出し

#### Step 3: 商品選択フォームを理解する

商品選択UIの実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | price-list-prices-add-product-ids-form.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/price-list-prices-add-product-ids-form.tsx` | 商品選択テーブル |

#### Step 4: 価格入力フォームを理解する

価格入力UIの実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | price-list-prices-add-prices-form.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/price-list-prices-add-prices-form.tsx` | DataGridによる価格入力 |

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

```
PriceListProductsAdd (price-list-prices-add.tsx)
    │
    ├─ usePriceList() - 価格表詳細取得
    │
    ├─ usePriceListCurrencyData() - 通貨/リージョン取得
    │
    └─ PriceListPricesAddForm
           │
           ├─ useForm()
           │
           ├─ useBatchPriceListPrices()
           │
           ├─ ProgressTabs
           │      │
           │      ├─ Tab.PRODUCT
           │      │      └─ PriceListPricesAddProductIdsForm
           │      │             └─ DataTable (商品選択)
           │      │
           │      └─ Tab.PRICE
           │             └─ PriceListPricesAddPricesForm
           │                    └─ DataGrid (価格入力)
           │
           └─ PrimaryButton
```

### データフロー図

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

URL param (id) ──────▶ usePriceList() ──────▶ price_list

通貨/リージョン ──────▶ usePriceListCurrencyData() ──────▶ currencies, regions

商品選択 ──────▶ useForm().product_ids

価格入力 ──────▶ useForm().products

Save押下 ──────▶ handleSubmit()
                   │
                   ├─▶ exctractPricesFromProducts()
                   │
                   └─▶ useBatchPriceListPrices()
                          │
                          └─▶ { create: prices }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| price-list-prices-add.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/price-list-prices-add.tsx` | ソース | ページコンポーネント |
| price-list-prices-add-form.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/price-list-prices-add-form.tsx` | ソース | メインフォーム |
| price-list-prices-add-product-ids-form.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/price-list-prices-add-product-ids-form.tsx` | ソース | 商品選択フォーム |
| price-list-prices-add-prices-form.tsx | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/price-list-prices-add-prices-form.tsx` | ソース | 価格入力フォーム |
| schema.ts | `packages/admin/dashboard/src/routes/price-lists/price-list-prices-add/components/price-list-prices-add-form/schema.ts` | ソース | バリデーションスキーマ |
| price-lists.tsx | `packages/admin/dashboard/src/hooks/api/price-lists.tsx` | ソース | API呼び出しフック |
