# 機能設計書 21-カート数量更新

## 概要

本ドキュメントは、ECモバイルアプリにおけるカート内商品の数量変更機能について設計仕様を定義する。

### 本機能の処理概要

本機能は、ショッピングカートに追加された商品の数量を変更し、合計金額を再計算する機能である。

**業務上の目的・背景**：ECサイトにおいて、ユーザーが購入予定商品の数量を柔軟に調整できることは、購買体験の向上に不可欠である。商品詳細画面に戻ることなくカート画面上で直接数量を変更できるようにすることで、購入フローの効率化と離脱率の低減を実現する。

**機能の利用シーン**：ユーザーがカート画面を閲覧中に、購入予定の商品数量を増減したい場合に利用される。例えば、複数個の購入を決定した場合や、予算に合わせて数量を減らしたい場合などに活用される。

**主要な処理内容**：
1. カート画面にて数量変更UIを提供する（QuantityView）
2. ユーザーが数量を変更すると、変更内容をローカルで保持
3. 「カート更新」ボタン押下で、変更された商品の数量をGraphQL API経由でサーバーに送信
4. サーバーからの応答を受けて、カート情報を再取得し画面を更新
5. 成功時は成功メッセージを表示、失敗時はエラーメッセージを表示

**関連システム・外部連携**：Bagisto GraphQL APIとの連携により、`updateItemToCart` mutationを使用してカート情報を更新する。

**権限による制御**：ゲストユーザー・ログインユーザーいずれも本機能を利用可能。カートはセッション単位で管理される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | カート画面 | 主画面 | カート内商品の数量変更処理 |

## 機能種別

CRUD操作（Update）/ バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cartItemId | String | Yes | カートアイテムID | 数値文字列であること |
| quantity | String | Yes | 変更後の数量 | 正の整数であること |

### 入力データソース

画面入力（QuantityViewウィジェットにてプラス/マイナスボタン操作、または直接入力）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 処理成功可否 |
| message | String | 処理結果メッセージ |
| cart | CartModel | 更新後のカート情報 |
| cart.itemsQty | int | カート内総商品数 |
| cart.grandTotal | double | 更新後の合計金額 |

### 出力先

- 画面表示（カート画面の商品リスト・合計金額表示を更新）
- グローバルカート数表示の更新（GlobalData.cartCountController）
- SharedPreferences（カート数の永続化）

## 処理フロー

### 処理シーケンス

```
1. ユーザーがQuantityViewで数量を変更
   └─ callBackにより変更値をCartListItemに通知
2. CartListItem._itemChangeで変更情報をselectedItemsリストに追加
   └─ cartItemIdと新しいquantityをMapとして保持
3. ユーザーが「Update Cart」ボタンを押下
   └─ ButtonView.onPressedでUpdateCartEventを発行
4. CartScreenBlocがイベントを受信
   └─ repository.updateItemToCartを呼び出し
5. CartScreenRepositoryがApiClientを経由でAPI呼び出し
   └─ GraphQL mutation updateItemToCartを実行
6. 成功時: UpdateCartState.successを発行
   └─ FetchCartDataEventでカートデータを再取得
7. 画面が更新され、成功メッセージを表示
```

### フローチャート

```mermaid
flowchart TD
    A[数量変更] --> B[selectedItemsに追加]
    B --> C[Update Cartボタン押下]
    C --> D[UpdateCartEvent発行]
    D --> E[CartScreenBloc処理]
    E --> F[API呼び出し]
    F --> G{成功?}
    G -->|Yes| H[UpdateCartState.success]
    H --> I[カートデータ再取得]
    I --> J[画面更新]
    J --> K[成功メッセージ表示]
    G -->|No| L[UpdateCartState.fail]
    L --> M[エラーメッセージ表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-021-01 | 数量下限 | 数量は1以上でなければならない | 数量変更時 |
| BR-021-02 | 在庫制限 | 在庫数を超える数量は設定できない | サーバー側バリデーション |
| BR-021-03 | 複数アイテム一括更新 | 複数商品の数量変更を一度のAPI呼び出しで実行可能 | Update Cart押下時 |

### 計算ロジック

小計 = 商品単価 × 数量
合計金額 = 各商品の小計の合計 + 配送料 - 割引額 + 税額

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カート数量更新 | cart_items | UPDATE | 指定されたカートアイテムの数量を更新 |
| カート合計再計算 | carts | UPDATE | カートの合計金額等を再計算して更新 |

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

#### cart_items

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | quantity | ユーザー指定の数量値 | cart_item_idで特定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ネットワークエラー | API通信失敗 | エラーメッセージを表示、リトライ可能 |
| - | 在庫不足 | 在庫数を超える数量を指定 | サーバーからのエラーメッセージを表示 |
| - | セッション切れ | カートセッションが無効 | カート再取得またはエラー表示 |

### リトライ仕様

自動リトライは行わない。ユーザーに再操作を促す。

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

サーバー側でトランザクション管理。cart_itemsテーブルの更新とcartsテーブルの再計算は同一トランザクション内で実行される。

## パフォーマンス要件

- API応答時間: 2秒以内を目標
- UI操作: 数量変更は即座に反映（ローカル状態更新）

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

- 認証: ゲストユーザーはセッションベース、ログインユーザーはトークン認証
- カートアクセス権限: 自身のカートアイテムのみ更新可能

## 備考

数量変更後は必ず「Update Cart」ボタンを押下する必要がある。変更内容は一時的にローカルで保持され、ボタン押下まではサーバーに反映されない。

---

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

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

### 推奨読解順序

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

まず、カートデータとAPI応答のデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cart_data_model.dart | `lib/screens/cart_screen/cart_model/cart_data_model.dart` | CartModel、Itemsクラスの構造を確認。quantityフィールドに注目 |
| 1-2 | add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | API応答モデル。CartModelを内包する構造 |

**読解のコツ**: Dart/Flutterの`@JsonSerializable()`アノテーションによるJSON変換パターンに注目。`part`ディレクティブで生成ファイル(.g.dart)を参照している。

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

UIからのイベント発火箇所を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cart_item.dart | `lib/screens/cart_screen/widget/cart_item.dart` | QuantityViewのcallBack処理とselectedItemsへの追加処理 |
| 2-2 | button_view.dart | `lib/screens/cart_screen/widget/button_view.dart` | UpdateCartEvent発行箇所 |

**主要処理フロー**:
1. **74-101行目**: QuantityViewウィジェットでの数量変更コールバック処理
2. **86-99行目**: _itemChangeメソッドでselectedItemsへのマップ追加
3. **127行目(button_view.dart)**: UpdateCartEvent発行

#### Step 3: BLoC層を理解する

状態管理とビジネスロジックの中心となるBLoCを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cart_screen_event.dart | `lib/screens/cart_screen/bloc/cart_screen_event.dart` | UpdateCartEventの定義（34-37行目） |
| 3-2 | cart_screen_state.dart | `lib/screens/cart_screen/bloc/cart_screen_state.dart` | UpdateCartStateの定義（98-109行目） |
| 3-3 | cart_screen_bloc.dart | `lib/screens/cart_screen/bloc/cart_screen_bloc.dart` | UpdateCartEventの処理（29-37行目） |

**主要処理フロー**:
- **29-37行目**: UpdateCartEventを受信し、repository経由でAPI呼び出し、成功/失敗状態を発行

#### Step 4: リポジトリ層とAPI層を理解する

実際のAPI呼び出し処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cart_screen_repository.dart | `lib/screens/cart_screen/bloc/cart_screen_repository.dart` | updateItemToCartメソッド（44-55行目） |
| 4-2 | api_client.dart | `lib/services/api_client.dart` | updateItemToCartメソッド（499-512行目） |
| 4-3 | mutation_query.dart | `lib/services/mutation_query.dart` | updateItemToCart GraphQL mutation（376-396行目） |

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

```
CartListItem (cart_item.dart)
    │
    ├─ QuantityView.callBack
    │      └─ _itemChange() → selectedItemsリスト更新
    │
ButtonView (button_view.dart)
    │
    └─ onPressed → UpdateCartEvent発行
           │
           └─ CartScreenBloc.mapEventToState (cart_screen_bloc.dart)
                  │
                  └─ CartScreenRepository.updateItemToCart
                         │
                         └─ ApiClient.updateItemToCart
                                │
                                └─ MutationQuery.updateItemToCart
```

### データフロー図

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

QuantityView ───▶ selectedItemsリスト ───▶ CartScreenBloc
   (UI)              (ローカル保持)            (状態管理)
                                                  │
                           ┌──────────────────────┘
                           ▼
                 CartScreenRepository
                           │
                           ▼
                     ApiClient
                           │
                           ▼
              GraphQL API (updateItemToCart)
                           │
                           ▼
                  AddToCartModel ───▶ UpdateCartState ───▶ UI更新
                   (応答データ)         (状態通知)        (画面反映)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cart_screen.dart | `lib/screens/cart_screen/cart_screen.dart` | ソース | カート画面メインWidget |
| cart_item.dart | `lib/screens/cart_screen/widget/cart_item.dart` | ソース | カートアイテムリストWidget |
| button_view.dart | `lib/screens/cart_screen/widget/button_view.dart` | ソース | カート操作ボタン群 |
| cart_screen_bloc.dart | `lib/screens/cart_screen/bloc/cart_screen_bloc.dart` | ソース | カート画面BLoC |
| cart_screen_event.dart | `lib/screens/cart_screen/bloc/cart_screen_event.dart` | ソース | BLoCイベント定義 |
| cart_screen_state.dart | `lib/screens/cart_screen/bloc/cart_screen_state.dart` | ソース | BLoC状態定義 |
| cart_screen_repository.dart | `lib/screens/cart_screen/bloc/cart_screen_repository.dart` | ソース | カート画面リポジトリ |
| cart_data_model.dart | `lib/screens/cart_screen/cart_model/cart_data_model.dart` | ソース | カートデータモデル |
| add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | ソース | カート追加応答モデル |
| api_client.dart | `lib/services/api_client.dart` | ソース | API通信クライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
