# 機能設計書 31-カートへ移動

## 概要

本ドキュメントは、ウィッシュリスト画面から商品をカートに移動する機能の設計を記述する。

### 本機能の処理概要

本機能は、ユーザーがウィッシュリスト（お気に入り）に登録した商品を、直接カートに移動するための機能である。

**業務上の目的・背景**：ECサイトにおいて、ユーザーは気になる商品をウィッシュリストに保存し、後日購入を検討することが多い。この機能により、ウィッシュリストから直接カートへ商品を追加でき、購入までのステップを削減し、コンバージョン率の向上に寄与する。また、商品をウィッシュリストから削除する手間も省け、シームレスな購入体験を提供できる。

**機能の利用シーン**：ユーザーがウィッシュリスト画面を開き、購入を決めた商品の「カートに追加」ボタンをタップした際に本機能が実行される。特にセール期間中や在庫が限られる商品など、素早く購入したい場合に有用である。

**主要な処理内容**：
1. ウィッシュリスト画面で「カートに追加」ボタンタップを検知
2. 商品タイプ（simple/virtual）とカスタマイズオプションの有無を確認
3. simpleまたはvirtual商品でカスタマイズオプションがない場合、GraphQL APIでカートへ移動
4. 商品オプション選択が必要な場合は、商品詳細画面へ遷移
5. カート移動成功後、ウィッシュリスト一覧を更新し、カート数を更新

**関連システム・外部連携**：GraphQL APIを介したBagistoバックエンドとの通信

**権限による制御**：ログイン済みユーザーのみ利用可能（ウィッシュリスト機能自体がログイン必須）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | ウィッシュリスト画面 | 主画面 | お気に入り商品をカートに移動 |

## 機能種別

データ連携（ウィッシュリスト → カート間の商品移動）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| productId | int | Yes | ウィッシュリスト商品ID | 正の整数であること |
| quantity | String | Yes | 購入数量 | "1"以上の数値文字列 |

### 入力データソース

- ウィッシュリスト画面のUIから取得
- 商品ID: WishlistData.id
- 数量: QuantityViewウィジェットで選択された値（デフォルト"1"）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 処理成功フラグ |
| message | String | 結果メッセージ |
| cart | Cart | 更新後のカート情報 |
| cart.itemsQty | int | カート内商品総数 |

### 出力先

- 画面表示: 成功/失敗通知トースト
- 状態更新: GlobalData.cartCountController（カート数バッジ更新）
- 画面遷移: ウィッシュリスト一覧の再取得・更新

## 処理フロー

### 処理シーケンス

```
1. ユーザーがカート追加ボタンをタップ
   └─ WishlistItemList.onTap実行
2. 商品タイプとオプションの確認
   └─ simple/virtualかつcustomizableOptionsが空かをチェック
3. 条件に応じた分岐処理
   └─ 条件を満たす場合: AddToCartWishlistEventを発火
   └─ 条件を満たさない場合: 商品詳細画面へ遷移
4. BlocがAPIを呼び出し
   └─ WishListRepository.callAddToCartAPi実行
5. ApiClient.moveFromWishlistToCartでGraphQL通信
   └─ moveToCart mutationを実行
6. レスポンス処理
   └─ 成功: カート数更新、通知表示、一覧更新
   └─ 失敗: エラー通知表示
```

### フローチャート

```mermaid
flowchart TD
    A[カートに追加ボタンタップ] --> B{商品タイプ確認}
    B -->|simple/virtual| C{カスタマイズオプション}
    B -->|configurable等| F[商品詳細画面へ遷移]
    C -->|なし| D[AddToCartWishlistEvent発火]
    C -->|あり| F
    D --> E[GraphQL API呼び出し]
    E --> G{API結果}
    G -->|成功| H[成功通知表示]
    G -->|失敗| I[エラー通知表示]
    H --> J[カート数更新]
    J --> K[ウィッシュリスト一覧更新]
    F --> L[ユーザーがオプション選択]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | 商品タイプ制限 | simple/virtual商品のみ直接カート追加可能 | カート追加ボタン押下時 |
| BR-31-02 | オプション必須確認 | カスタマイズオプションがある商品は詳細画面へ誘導 | カート追加ボタン押下時 |
| BR-31-03 | ウィッシュリスト自動削除 | カート移動成功時、ウィッシュリストから自動削除 | API成功時 |
| BR-31-04 | 在庫確認 | isSaleableがfalseの場合はボタン無効化 | 画面表示時 |

### 計算ロジック

- 数量はユーザーがQuantityViewで指定（デフォルト: 1）
- カート移動後の総数量はAPIレスポンスのcart.itemsQtyを使用

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カート移動 | wishlist_items | DELETE | ウィッシュリストから商品削除 |
| カート移動 | cart_items | INSERT/UPDATE | カートに商品追加または数量更新 |

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

#### wishlist_items

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | id | 指定されたproductId | バックエンドで処理 |

#### cart_items

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | product_id, quantity | 商品ID、指定数量 | バックエンドで処理 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | graphqlErrors | API通信失敗 | エラー通知表示、再試行を促す |
| - | ネットワークエラー | 通信不可 | エラー通知表示 |
| - | 在庫切れ | 商品が販売不可 | ボタン無効化（opacity 0.4） |

### リトライ仕様

自動リトライなし。ユーザーが再度ボタンをタップする必要がある。

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

バックエンドAPIでトランザクション管理。ウィッシュリスト削除とカート追加は一括処理。

## パフォーマンス要件

- API応答時間: 3秒以内
- ローディング表示: 処理中はLoaderコンポーネントを表示

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

- 認証トークンによるAPI呼び出し
- ユーザーは自身のウィッシュリスト商品のみ操作可能
- Cookieベースのセッション管理

## 備考

- 商品タイプがconfigurable/bundle/downloadable/grouped/bookingの場合は商品詳細画面で追加オプションを選択する必要がある

---

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

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

### 推奨読解順序

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

ウィッシュリストと商品の関係、およびカート移動リクエストの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wishlist_model.dart | `lib/screens/wishList/data_model/wishlist_model.dart` | WishListData、WishlistDataクラスの構造を把握 |
| 1-2 | add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | API応答モデルAddToCartModelの構造を確認 |

**読解のコツ**: DartのfactoryコンストラクタでfromJsonが定義されており、JSONからオブジェクト変換される仕組みを確認する。

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

ユーザー操作の起点となるUI部分を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | wishlist_Item_list.dart | `lib/screens/wishList/view/widget/wishlist_Item_list.dart` | カート追加ボタンのonTap処理 |

**主要処理フロー**:
1. **160-176行目**: 商品タイプとカスタマイズオプションのチェック
2. **168-176行目**: AddToCartWishlistEventの発火
3. **177-195行目**: オプション必要時の商品詳細画面遷移

#### Step 3: Bloc（状態管理層）を理解する

イベント発火からリポジトリ呼び出しまでの流れを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | wishlist_event.dart | `lib/screens/wishList/bloc/wishlist_event.dart` | AddToCartWishlistEventの定義 |
| 3-2 | wishlist_bloc.dart | `lib/screens/wishList/bloc/wishlist_bloc.dart` | イベント処理とリポジトリ呼び出し |

**主要処理フロー**:
- **49-65行目**: AddToCartWishlistEventの処理、callAddToCartAPi呼び出し

#### Step 4: Repository（データアクセス層）を理解する

APIクライアントへの橋渡しを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | wishlist_repository.dart | `lib/screens/wishList/bloc/wishlist_repository.dart` | callAddToCartAPiメソッド |

**主要処理フロー**:
- **52-63行目**: moveFromWishlistToCartの呼び出し

#### Step 5: APIクライアントを理解する

GraphQL通信の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | api_client.dart | `lib/services/api_client.dart` | moveFromWishlistToCartメソッド |

**主要処理フロー**:
- **598-611行目**: moveToCart mutationの実行

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

```
WishlistItemList (UI)
    │
    ├─ WishListBloc.add(AddToCartWishlistEvent)
    │      │
    │      └─ WishListRepository.callAddToCartAPi()
    │             │
    │             └─ ApiClient.moveFromWishlistToCart()
    │                    │
    │                    └─ GraphQL mutation: moveToCart
    │
    └─ 状態更新
           ├─ AddToCartWishlistState.success
           │      └─ GlobalData.cartCountController更新
           │
           └─ FetchWishListEvent（一覧再取得）
```

### データフロー図

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

商品ID ─────────────▶ WishListBloc ───────────▶ 成功通知
  │                       │
数量 ──────────────────────┘                   カート数更新
                          │
                    WishListRepository         ウィッシュリスト
                          │                    一覧更新
                    ApiClient
                          │
                    GraphQL Server
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| wishlist_screen.dart | `lib/screens/wishList/view/wishlist_screen.dart` | ソース | ウィッシュリスト画面本体 |
| wishlist_Item_list.dart | `lib/screens/wishList/view/widget/wishlist_Item_list.dart` | ソース | 商品リストウィジェット |
| wishlist_bloc.dart | `lib/screens/wishList/bloc/wishlist_bloc.dart` | ソース | 状態管理Bloc |
| wishlist_event.dart | `lib/screens/wishList/bloc/wishlist_event.dart` | ソース | イベント定義 |
| wishlist_state.dart | `lib/screens/wishList/bloc/wishlist_state.dart` | ソース | 状態定義 |
| wishlist_repository.dart | `lib/screens/wishList/bloc/wishlist_repository.dart` | ソース | リポジトリ層 |
| api_client.dart | `lib/services/api_client.dart` | ソース | API通信クライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
| quantity_view.dart | `lib/screens/product_screen/view/quantity_view.dart` | ソース | 数量選択ウィジェット |
