# 機能設計書 44-再注文

## 概要

本ドキュメントは、ECモバイルアプリケーションにおける再注文機能の設計仕様を定義する。過去の注文内容を再度カートに追加し、簡単に同じ商品を再購入できる機能である。

### 本機能の処理概要

この機能は、注文詳細画面から過去の注文商品を一括でカートに追加する処理を提供する。気に入った商品や定期的に購入する商品の再購入を簡素化する。

**業務上の目的・背景**：ECサイトにおいて、リピート購入は売上の重要な部分を占める。ユーザーが過去に満足した商品を簡単に再購入できる機能を提供することで、購買のハードルを下げ、リピート率を向上させる。また、手動で商品を検索してカートに追加する手間を省くことで、ユーザー体験を向上させる。

**機能の利用シーン**：ユーザーが注文詳細画面で「再注文」ボタンをタップした際に利用される。消耗品の定期購入、気に入った商品の追加購入、贈り物として同じ商品を再度購入する場合などに使用される。

**主要な処理内容**：
1. 再注文ボタンの表示判定（バンドル商品を含まない場合のみ）
2. GraphQL APIで再注文リクエスト送信
3. 注文に含まれるすべての商品をカートに追加
4. 処理結果の通知
5. 成功時のカート画面への遷移

**関連システム・外部連携**：バックエンドのBagisto GraphQL APIと連携し、再注文処理を実行する。サーバーサイドで在庫確認、価格更新、カートへの追加処理を行う。

**権限による制御**：ログイン済みユーザーのみがアクセス可能。ユーザーは自身の注文のみを再注文できる。バンドル商品を含む注文は再注文不可。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | 注文詳細画面 | 主画面 | 再注文ボタン押下、処理実行 |
| 12 | カート画面 | 遷移先画面 | 再注文成功後にカート画面へ遷移 |

## 機能種別

データ更新 / カート追加 / API連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String | Yes | 注文の内部ID（文字列形式） | 正の整数を文字列化 |

### 入力データソース

- 画面データ：OrderDetailモデルから取得したorderIdをString変換
- ユーザーセッション：認証トークン（SharedPreferencesから取得）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 処理成功フラグ |
| message | String | 処理結果メッセージ |
| graphqlErrors | String | エラー詳細（失敗時） |

### 出力先

- 画面表示：成功/失敗通知メッセージ
- 画面遷移：成功時はカート画面へ遷移

## 処理フロー

### 処理シーケンス

```
1. 再注文ボタン表示判定
   └─ 注文商品にバンドル商品が含まれない場合のみ表示
2. 再注文ボタン押下
   └─ ReOrderEvent発行
3. API呼び出し
   └─ OrderDetailRepositoryでreOrderCustomerOrder実行
4. レスポンス処理
   └─ AddToCartModelにデシリアライズ
5. 結果通知
   └─ 成功時：successNotification、失敗時：errorNotification
6. 画面遷移
   └─ 成功時：2秒後にNavigator.pushNamedでカート画面へ
```

### フローチャート

```mermaid
flowchart TD
    A[注文詳細画面表示] --> B{バンドル商品含む?}
    B -->|Yes| C[再注文ボタン非表示]
    B -->|No| D[再注文ボタン表示]
    D --> E[再注文ボタン押下]
    E --> F[ReOrderEvent発行]
    F --> G[reOrderCustomerOrder API呼び出し]
    G --> H{API成功?}
    H -->|Yes| I{success == true?}
    H -->|No| J[エラー通知表示]
    I -->|Yes| K[成功通知表示]
    I -->|No| L[エラー通知表示]
    K --> M[2秒待機]
    M --> N[Navigator.pushNamed]
    N --> O[カート画面]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-44-01 | バンドル商品除外 | バンドル商品を含む注文は再注文不可 | items.type='bundle'を含む場合 |
| BR-44-02 | 自己注文のみ | ユーザーは自身の注文のみ再注文可能 | 常時 |
| BR-44-03 | 在庫確認 | 再注文時にサーバー側で在庫を確認 | API処理時 |
| BR-44-04 | 価格更新 | 再注文時は現在の価格が適用される | API処理時 |
| BR-44-05 | 遷移タイミング | 再注文成功後2秒待機してからカート画面遷移 | 成功時 |

### 計算ロジック

再注文可否判定：
```dart
if (orderDetailModel?.items?.any((item) => item.type == 'bundle') != true) {
  // 再注文ボタンを表示
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 再注文処理 | cart | INSERT/UPDATE | カートに商品を追加 |
| 再注文処理 | cart_items | INSERT | カート商品明細を追加 |
| 再注文処理 | product_inventories | SELECT | 在庫確認 |

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

#### cart / cart_items（GraphQL API経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | cart_id, product_id, quantity, etc. | 注文に含まれる商品情報 | サーバーサイドで処理 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | API通信エラー | ネットワーク接続不可 | エラー通知表示 |
| - | 認証エラー | セッション切れ | エラー通知表示 |
| - | 在庫不足 | 商品の在庫がない | エラーメッセージ表示 |
| - | 商品無効 | 商品が削除または非公開 | エラーメッセージ表示 |
| - | 処理失敗 | サーバー内部エラー | "Something went wrong"表示 |

### リトライ仕様

- 自動リトライなし
- ユーザーが再度再注文ボタンを押下することで再試行可能

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

- フロントエンドからは単一API呼び出し
- サーバーサイドでトランザクション管理（在庫確認、カート追加の整合性保証）

## パフォーマンス要件

- 再注文処理完了：3秒以内
- 結果通知表示後の画面遷移：2秒の待機後

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

- 認証トークンを使用したAPI呼び出し
- 注文IDによるアクセス制御（サーバーサイドで所有者確認）

## 備考

- 再注文時は現在の商品価格が適用されるため、注文時と価格が異なる可能性がある
- 在庫不足の場合は部分的に追加される可能性あり（サーバー実装依存）
- AddToCartModelはカート操作の共通レスポンスモデル

---

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

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

### 推奨読解順序

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

APIレスポンスの構造を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | AddToCartModelの構造（success, message, graphqlErrors） |

**読解のコツ**: 再注文APIはカート追加と同じAddToCartModelを返す。successフラグで成功/失敗を判定。

#### Step 2: イベント定義を理解する

再注文処理に関連するイベントを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | order_detail_event.dart | `lib/screens/order_detail/bloc/order_detail_event.dart` | ReOrderEventの定義 |

**主要処理フロー**:
- **43-50行目**: ReOrderEventの定義（idパラメータのみ）

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

再注文処理のビジネスロジックを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | order_detail_bloc.dart | `lib/screens/order_detail/bloc/order_detail_bloc.dart` | ReOrderEventのハンドリング |

**主要処理フロー**:
- **58-70行目**: ReOrderEventの処理
  - **60行目**: repository.reOrderCustomerOrder(event.id)でAPI呼び出し
  - **61-62行目**: success==trueならReOrderState.success
  - **64行目**: success!=trueならReOrderState.fail

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

API呼び出しの実装を確認。

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

**主要処理フロー**:
- **52-62行目**: reOrderCustomerOrderでApiClient.reOrderCustomerOrder呼び出し

#### Step 5: UI実装を理解する

再注文ボタンの実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | order_detail_tile.dart | `lib/screens/order_detail/widgets/order_detail_tile.dart` | 再注文ボタンの表示条件と処理 |

**主要処理フロー**:
- **231-233行目**: バンドル商品チェック（type=='bundle'を含まない場合のみ表示）
- **234-251行目**: GestureDetectorで再注文ボタン実装
- **236-237行目**: ReOrderEvent発行

#### Step 6: 結果処理を理解する

再注文結果のハンドリングを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | order_detail.dart | `lib/screens/order_detail/view/order_detail.dart` | BlocConsumerのlistenerでReOrderState処理 |

**主要処理フロー**:
- **72-82行目**: ReOrderStateのハンドリング
  - **73-77行目**: 成功時通知＋2秒後カート画面遷移
  - **79-81行目**: 失敗時エラー通知

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

```
OrderDetailTile (Widget)
    │
    ├─ GestureDetector [再注文]
    │      │
    │      └─ ReOrderEvent発行
    │
    └─ OrderDetailBloc
           │
           └─ ReOrderState
                  │
                  └─ OrderDetailRepositoryImp.reOrderCustomerOrder()
                         │
                         └─ ApiClient.reOrderCustomerOrder()
```

### データフロー図

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

再注文ボタン押下
       │
       ▼
ReOrderEvent(orderId) ───▶ OrderDetailBloc
                                  │
                                  ▼
                        OrderDetailRepository.reOrderCustomerOrder()
                                  │
                                  ▼
                        ApiClient (GraphQL mutation)
                                  │
                                  ▼
                           AddToCartModel
                                  │
                                  ▼
                        ReOrderState ───▶ 成功/失敗通知
                                              │
                                              ▼ [成功時]
                                          カート画面遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| order_detail.dart | `lib/screens/order_detail/view/order_detail.dart` | ソース | 結果ハンドリング（listener） |
| order_detail_bloc.dart | `lib/screens/order_detail/bloc/order_detail_bloc.dart` | ソース | 再注文処理のBLoC |
| order_detail_event.dart | `lib/screens/order_detail/bloc/order_detail_event.dart` | ソース | ReOrderEvent定義 |
| order_detail_state.dart | `lib/screens/order_detail/bloc/order_detail_state.dart` | ソース | ReOrderState定義 |
| order_detail_repository.dart | `lib/screens/order_detail/bloc/order_detail_repository.dart` | ソース | reOrderCustomerOrderメソッド |
| order_detail_tile.dart | `lib/screens/order_detail/widgets/order_detail_tile.dart` | ソース | 再注文ボタンUI |
| add_to_cart_model.dart | `lib/screens/cart_screen/cart_model/add_to_cart_model.dart` | ソース | APIレスポンスモデル |
