# 機能設計書 39-支払方法選択

## 概要

本ドキュメントは、チェックアウト時の支払方法選択と保存機能の設計を記述する。

### 本機能の処理概要

本機能は、チェックアウト画面のステップ3で、利用可能な支払方法の一覧を表示し、ユーザーが希望する支払方法を選択する機能である。

**業務上の目的・背景**：ECサイトにおいて、支払方法の選択肢はユーザーの購入決定に大きく影響する。本機能により、複数の支払オプション（クレジットカード、銀行振込、代金引換、PayPalなど）から選択でき、ユーザーの利便性を向上させる。

**機能の利用シーン**：チェックアウト画面のステップ3（支払方法選択）で本機能が使用される。配送方法選択完了後に自動的に支払方法が取得される。

**主要な処理内容**：
1. 配送方法をもとにGraphQL APIで配送方法保存と支払方法一覧取得
2. 利用可能な支払方法をラジオボタンリストで表示（フィルタリング済み）
3. ユーザーが支払方法を選択
4. 選択した支払方法IDをcallBackで親画面に渡す
5. 合計金額を更新表示

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

**権限による制御**：ログインユーザー・ゲストユーザー共に利用可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | チェックアウト画面 | 主画面 | 支払方法の選択と保存 |

## 機能種別

データ取得・選択・保存処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| shippingId | String? | Yes | 選択された配送方法コード | - |
| callBack | Function | Yes | 選択完了時のコールバック | - |
| priceCallback | ValueChanged<String>? | No | 価格更新時のコールバック | - |
| total | String? | No | 現在の合計金額 | - |
| paymentMethods | PaymentMethods? | No | 既取得の支払方法（スキップ時） | - |

### 入力データソース

- 親画面（CheckoutScreen）から渡される配送方法コード

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| paymentMethods | List<PaymentMethod> | 支払方法一覧 |
| paymentMethods[].method | String | 支払方法コード |
| paymentMethods[].methodTitle | String | 支払方法名 |
| cart.formattedPrice.grandTotal | String | 合計金額（フォーマット済み） |

### 出力先

- 画面表示: 支払方法ラジオボタンリスト
- 親画面への callBack: 選択した支払方法コード
- 親画面への priceCallback: 更新後の合計金額

## 処理フロー

### 処理シーケンス

```
1. 支払ビュー表示時に条件確認
   └─ paymentMethodsが既にある場合はAPI呼び出しスキップ
2. なければCheckOutPaymentEvent発火
   └─ build内でBloc.add実行
3. Blocがリポジトリを通じてAPI呼び出し
   └─ CheckOutPaymentRepository.saveCheckOutPayment
4. ApiClient.saveShippingMethodsでGraphQL通信
   └─ saveShippingMethod mutationを実行
5. 配送方法保存と同時に支払方法一覧を取得
   └─ PaymentMethodsレスポンスにpaymentMethods含む
6. 利用可能な支払方法をフィルタリング
   └─ availablePaymentMethodsリストでフィルタ
7. 支払方法をラジオボタンリストで表示
   └─ RadioButtonGroupウィジェット使用
8. ユーザーが支払方法を選択
   └─ onChange callbackで選択検知
9. callBackで親画面に支払方法コードを渡す
10. priceCallbackで合計金額を更新
```

### フローチャート

```mermaid
flowchart TD
    A[支払ビュー表示] --> B{支払方法取得済み?}
    B -->|Yes| C[支払方法リスト表示]
    B -->|No| D[配送方法保存API呼び出し]
    D --> E{API成功?}
    E -->|Yes| F[支払方法をフィルタリング]
    E -->|No| G[エラー表示]
    F --> C
    C --> H[ユーザーが支払方法選択]
    H --> I[callBackで親画面に通知]
    I --> J[priceCallbackで金額更新]
    J --> K[次ステップへ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | 配送方法保存 | 支払方法取得時に配送方法も保存される | API呼び出し時 |
| BR-39-02 | 支払方法フィルタ | availablePaymentMethodsに含まれる方法のみ表示 | リスト表示時 |
| BR-39-03 | 合計金額更新 | 支払方法取得時にgrandTotalを表示更新 | API成功時 |
| BR-39-04 | スキップ対応 | ダウンロード商品で配送スキップ時、paymentMethodsが渡される | 該当時 |

### 計算ロジック

- 合計金額はcart.formattedPrice.grandTotalを使用

### 利用可能支払方法

availablePaymentMethodsリストで以下の支払方法がフィルタリングされる（設定依存）。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 配送方法保存 | cart_shipping_rates | INSERT/UPDATE | カートの配送方法保存 |

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

#### cart_shipping_rates

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | cart_id, method | カートID、配送方法コード | バックエンドで処理 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | graphqlErrors | API通信失敗 | エラーメッセージ表示 |

### リトライ仕様

自動リトライなし。

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

バックエンドAPIでトランザクション管理。

## パフォーマンス要件

- API応答時間: 3秒以内

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

- 決済情報は本画面では扱わない（選択のみ）
- 実際の決済処理は注文確定時に行われる

## 備考

- 支払方法選択は必須（未選択では注文確定不可）

---

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

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

### 推奨読解順序

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

支払方法データのモデル構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | checkout_save_shipping_model.dart | `lib/screens/checkout/data_model/checkout_save_shipping_model.dart` | PaymentMethods、PaymentMethodクラスの構造 |

**読解のコツ**: PaymentMethodsにpaymentMethodsリストとcartが含まれ、各PaymentMethodにmethodとmethodTitleがある。

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

支払方法選択ビューの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | checkout_payment_view.dart | `lib/screens/checkout/checkout_payment/view/checkout_payment_view.dart` | メインビュー |

**主要処理フロー**:
- **45-59行目**: _paymentBlocメソッドでAPI呼び出し制御
- **62-84行目**: buildUIメソッドで状態に応じたUI構築
- **86-129行目**: _paymentMethodsメソッドで支払方法リスト表示

#### Step 3: Bloc/Repositoryを理解する

API呼び出しの流れを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | checkout_payment_bloc.dart | `lib/screens/checkout/checkout_payment/bloc/checkout_payment_bloc.dart` | 状態管理Bloc |
| 3-2 | checkout_payment_repository.dart | `lib/screens/checkout/checkout_payment/bloc/checkout_payment_repository.dart` | リポジトリ層 |

**主要処理フロー**:
- checkout_payment_repository.dart **24-33行目**: saveShippingMethods呼び出し

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

```
CheckoutPaymentView (UI)
    │
    ├─ _paymentBloc: CheckOutPaymentBloc.add(CheckOutPaymentEvent)
    │      │
    │      └─ CheckOutPaymentRepository.saveCheckOutPayment(shippingMethod)
    │             │
    │             └─ ApiClient.saveShippingMethods(shippingMethod)
    │                    │
    │                    └─ GraphQL mutation: saveShippingMethod
    │
    ├─ UI描画
    │      ├─ priceCallback（合計金額更新）
    │      └─ RadioButtonGroup（支払方法リスト）
    │
    └─ onChange callback
           └─ 親画面へ支払方法コードを通知
```

### データフロー図

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

配送方法コード ────────▶ CheckOutPaymentBloc ────▶ 支払方法リスト
                              │
                        CheckOutPaymentRepository
                              │
                        ApiClient.saveShippingMethods
                              │
                        GraphQL Server

支払選択 ──────────────▶ callBack ─────────────▶ 親画面へ通知
                              │                      │
                        priceCallback            paymentId更新
                              │
                        合計金額更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| checkout_payment_view.dart | `lib/screens/checkout/checkout_payment/view/checkout_payment_view.dart` | ソース | 支払方法選択メインビュー |
| checkout_payment_bloc.dart | `lib/screens/checkout/checkout_payment/bloc/checkout_payment_bloc.dart` | ソース | 状態管理Bloc |
| checkout_payment_event.dart | `lib/screens/checkout/checkout_payment/bloc/checkout_payment_event.dart` | ソース | イベント定義 |
| checkout_payment_state.dart | `lib/screens/checkout/checkout_payment/bloc/checkout_payment_state.dart` | ソース | 状態定義 |
| checkout_payment_repository.dart | `lib/screens/checkout/checkout_payment/bloc/checkout_payment_repository.dart` | ソース | リポジトリ層 |
| checkout_save_shipping_model.dart | `lib/screens/checkout/data_model/checkout_save_shipping_model.dart` | ソース | データモデル |
| api_client.dart | `lib/services/api_client.dart` | ソース | API通信クライアント |
