# 機能設計書 30-支払いセッション管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける支払いセッション（Payment Session）の管理機能について記載する。

### 本機能の処理概要

本機能は、支払いコレクションに紐づく支払いセッションの作成・更新・削除・認可を行う機能である。支払いセッションは、外部決済プロバイダー（Stripe、PayPal等）との連携において、決済処理の状態を管理する中間エンティティである。顧客が選択した支払い方法に基づいてセッションを作成し、認可処理を経て支払いレコードを生成する。

**業務上の目的・背景**：ECサイトの決済処理では、顧客が支払い情報を入力してから実際に決済が完了するまでに複数のステップが存在する。支払いセッションは、このプロセスにおける「支払い意図」を表し、決済プロバイダーとの通信状態、認可状態などを追跡する。これにより、決済の途中離脱への対応や、複数の支払い方法の切り替えが可能となる。

**機能の利用シーン**：
- チェックアウト時に支払い方法を選択した時
- 顧客が支払い情報を入力して決済を開始する時
- 支払いセッションの認可を行う時
- 支払い方法を変更する時（既存セッション削除→新規セッション作成）

**主要な処理内容**：
1. 支払いセッションの作成
2. 支払いセッションの更新
3. 支払いセッションの削除
4. 支払いセッションの認可（authorize）
5. 認可完了時の支払いレコード生成

**関連システム・外部連携**：
- 支払いプロバイダー: Stripe、PayPal、System Provider等
- 支払いコレクション: 親エンティティ
- アカウントホルダー: 顧客の決済アカウント情報

**権限による制御**：Store APIから顧客が自身のカートに関連する支払いセッションを操作可能。Admin APIでは管理者が全ての支払いセッションを管理可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | チェックアウト画面（支払い） | 主画面 | 支払いセッション作成・認可 |
| - | 管理画面（注文詳細） | 参照画面 | 支払いセッション状態確認 |

## 機能種別

CRUD操作

## 入力仕様

### 入力パラメータ

#### 支払いセッション作成

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| payment_collection_id | string | Yes | 支払いコレクションID | 存在すること |
| provider_id | string | Yes | 支払いプロバイダーID | 有効なプロバイダー |
| data | object | No | プロバイダー固有データ | - |
| context | object | No | コンテキスト情報 | - |

#### 支払いセッション認可

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | 支払いセッションID | 存在すること |
| context | object | No | 認可コンテキスト | - |

### 入力データソース

- Store API: POST /store/payment-collections/{id}/payment-sessions（セッション作成）
- 内部ワークフロー（認可処理）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| payment_session | PaymentSessionDTO | 支払いセッション情報 |
| payment_session.id | string | セッションID（paysesプレフィックス） |
| payment_session.currency_code | string | 通貨コード |
| payment_session.amount | BigNumber | 金額 |
| payment_session.provider_id | string | プロバイダーID |
| payment_session.data | object | プロバイダー固有データ |
| payment_session.context | object | コンテキスト情報 |
| payment_session.status | PaymentSessionStatus | ステータス |
| payment_session.authorized_at | DateTime | 認可日時 |
| payment_session.payment | PaymentDTO | 認可後の支払いレコード |

### 出力先

- APIレスポンス（JSON形式）
- データベース（payment_sessionテーブル）
- 外部決済プロバイダー

## 処理フロー

### 処理シーケンス（作成）

```
1. リクエスト受信
   └─ payment_collection_id, provider_id, dataを取得

2. 支払いコレクションの取得
   └─ 金額、通貨コードを取得

3. 顧客情報の取得（ある場合）
   └─ アカウントホルダー情報を取得または作成

4. 既存セッションの削除
   └─ 現在はスプリット支払い未対応のため、既存セッションを削除

5. 支払いセッション作成
   └─ createPaymentSessionStep実行
      ├─ DBにセッションレコード作成
      └─ プロバイダーのcreateSessionを呼び出し

6. プロバイダーからの応答でセッション更新
   └─ data、statusを更新

7. レスポンス返却
   └─ 作成されたセッション情報を返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[支払いコレクション取得]
    B --> C{顧客ID?}
    C -->|Yes| D[アカウントホルダー取得/作成]
    C -->|No| E[既存セッション削除]
    D --> E
    E --> F[セッションレコード作成]
    F --> G[プロバイダーcreateSession]
    G --> H{成功?}
    H -->|No| I[セッション削除]
    I --> J[エラー返却]
    H -->|Yes| K[セッション更新]
    K --> L[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-30-01 | 単一セッション | 現在、コレクションにつき1つのアクティブセッションのみ | セッション作成時 |
| BR-30-02 | ステータス遷移 | PENDING → AUTHORIZED or ERROR | 認可処理時 |
| BR-30-03 | 認可後支払い作成 | 認可成功時にPaymentレコードを自動作成 | 認可成功時 |
| BR-30-04 | 冪等性 | 既に認可済みの場合は既存Paymentを返却 | 認可リクエスト時 |
| BR-30-05 | プロバイダー連携 | セッション操作はプロバイダーAPIと同期 | 常時 |
| BR-30-06 | 自動キャプチャ | プロバイダーがCAPTURED返却時は自動キャプチャ | 認可時 |

### 計算ロジック

```
■ セッション金額
amount = 支払いコレクションのamount

■ 通貨コード
currency_code = 支払いコレクションのcurrency_code
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | payment_session | INSERT | セッションレコード作成 |
| 更新 | payment_session | UPDATE | ステータス、data更新 |
| 削除 | payment_session | DELETE | セッションレコード削除 |
| 認可時 | payment | INSERT | 支払いレコード作成 |

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

#### payment_session

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | id | 自動生成（paysesプレフィックス） | 主キー |
| INSERT/UPDATE | currency_code | 通貨コード | 必須 |
| INSERT/UPDATE | amount | 金額 | BigNumber |
| INSERT/UPDATE | provider_id | プロバイダーID | 必須 |
| INSERT/UPDATE | data | プロバイダー固有データ | JSON、デフォルト{} |
| INSERT/UPDATE | context | コンテキスト | JSON、NULL許可 |
| INSERT/UPDATE | status | ステータス | 列挙型、デフォルトPENDING |
| INSERT/UPDATE | authorized_at | 認可日時 | NULL許可 |
| INSERT/UPDATE | payment_collection_id | 支払いコレクションID | 外部キー |
| INSERT/UPDATE | metadata | メタデータ | JSON、NULL許可 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | 支払いコレクションが存在しない | 有効なIDを指定 |
| NOT_FOUND | MedusaError | 支払いセッションが存在しない | 有効なIDを指定 |
| NOT_ALLOWED | MedusaError | 認可が拒否された | 支払い情報を確認 |
| PROVIDER_ERROR | MedusaError | プロバイダーAPIエラー | 再試行または別プロバイダー選択 |

### リトライ仕様

プロバイダーAPIエラー時は、プロバイダーの実装に応じてリトライが行われる場合がある。

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

- セッション作成とプロバイダー呼び出しは部分的にトランザクション管理
- プロバイダー呼び出し失敗時はセッションを削除してロールバック
- 認可処理とPayment作成は同一トランザクション内

## パフォーマンス要件

- セッション作成: プロバイダー応答時間 + 500ms以内
- 認可: プロバイダー応答時間 + 1秒以内

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

- 支払い情報は機密情報として適切に保護
- プロバイダーとの通信はHTTPS必須
- dataフィールドにカード情報を直接保存しない（トークン化）
- idempotency_keyを使用して重複処理を防止

## 備考

- PaymentSessionStatus列挙型: PENDING, AUTHORIZED, REQUIRES_MORE, ERROR, CANCELED
- 現在のバージョンではスプリット支払い（複数セッション）未対応
- プロバイダーがCAPTURED返却時は自動的にキャプチャ処理も実行

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | payment-session.ts | `packages/modules/payment/src/models/payment-session.ts` | 支払いセッションモデル定義 |

**主要処理フロー（payment-session.ts）**:
- **5-37行目**: PaymentSessionモデル定義
- **7行目**: IDプレフィックスはpayses
- **8-10行目**: currency_code, amount, provider_id
- **11行目**: dataはJSONでデフォルト{}
- **12行目**: contextはJSON、NULL許可
- **13-15行目**: statusはPaymentSessionStatus列挙型、デフォルトPENDING
- **16行目**: authorized_atは認可日時
- **17-21行目**: payment_collectionとのbelongsTo関連
- **22-26行目**: paymentとのhasOne関連

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | route.ts | `packages/medusa/src/api/store/payment-collections/[id]/payment-sessions/route.ts` | Store APIセッション作成 |

**主要処理フロー**:
- **9-39行目**: POST メソッド - セッション作成（createPaymentSessionsWorkflow使用）
- **17-24行目**: ワークフロー入力の構築（collection_id, provider_id, customer_id, data）

#### Step 3: ワークフローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create-payment-session.ts | `packages/core/core-flows/src/payment-collection/workflows/create-payment-session.ts` | セッション作成ワークフロー |

**主要処理フロー**:
- **73-208行目**: createPaymentSessionsWorkflowの定義
- **78-83行目**: 支払いコレクション取得
- **85-146行目**: 顧客情報取得、アカウントホルダー処理
- **167-183行目**: セッション入力の構築
- **185-193行目**: 既存セッション削除
- **199-204行目**: セッション作成（parallelize）

#### Step 4: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | payment-module.ts | `packages/modules/payment/src/services/payment-module.ts` | 支払いモジュールサービス |

**主要処理フロー**:
- **360-416行目**: createPaymentSession - セッション作成
- **418-438行目**: createPaymentSession_ - 内部実装
- **440-476行目**: updatePaymentSession - セッション更新
- **478-495行目**: deletePaymentSession - セッション削除
- **497-579行目**: authorizePaymentSession - セッション認可

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

```
POST /store/payment-collections/{id}/payment-sessions
    │
    └─ createPaymentSessionsWorkflow
           │
           ├─ useRemoteQueryStep (コレクション取得)
           │
           ├─ (顧客IDがある場合)
           │      ├─ useRemoteQueryStep (顧客取得)
           │      └─ createPaymentAccountHolderStep
           │
           ├─ deletePaymentSessionsWorkflow (既存削除)
           │
           └─ createPaymentSessionStep
                  │
                  ├─ PaymentModuleService.createPaymentSession
                  │      └─ paymentSessionService_.create
                  │
                  └─ PaymentProviderService.createSession
                         └─ Provider.initiatePayment
```

### データフロー図

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

collection_id    ───┐
provider_id      ───┼──▶ createPaymentSessionsWorkflow ───▶ 作成されたセッション
customer_id      ───┤         │
data             ───┘         ├─▶ 既存セッション削除
                              │
                              ├─▶ DBセッション作成 ───▶ payment_session
                              │
                              └─▶ プロバイダーAPI呼び出し
                                     │
                                     └─▶ セッション更新 (data, status)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| payment-session.ts | `packages/modules/payment/src/models/payment-session.ts` | ソース | 支払いセッションモデル |
| route.ts | `packages/medusa/src/api/store/payment-collections/[id]/payment-sessions/route.ts` | ソース | Store API |
| create-payment-session.ts | `packages/core/core-flows/src/payment-collection/workflows/create-payment-session.ts` | ソース | セッション作成ワークフロー |
| payment-module.ts | `packages/modules/payment/src/services/payment-module.ts` | ソース | 支払いモジュールサービス |
| payment-provider.ts | `packages/modules/payment/src/services/payment-provider.ts` | ソース | プロバイダーサービス |
