# 機能設計書 48-注文完了

## 概要

本ドキュメントは、注文を確定し支払処理を実行する機能の設計を定義するものである。

### 本機能の処理概要

注文確認ページで「注文する」ボタンをクリックした際に、注文データを作成し、支払処理を実行する機能である。

**業務上の目的・背景**：チェックアウトプロセスの最終段階として、顧客の注文を確定し、決済処理を行う。この処理により、カートの内容が正式な注文として記録され、支払が開始される。ECサイトの中核機能であり、売上に直結する重要な処理である。

**機能の利用シーン**：注文確認ページで最終確認を行った後、「注文する」または「支払う」ボタンをクリックした際に実行される。デジタル商品の場合は撤回権への同意チェックが必要。

**主要な処理内容**：
1. 顧客のログイン状態を確認
2. アフィリエイト/キャンペーントラッキング情報の追加
3. OrderServiceを通じて注文を作成
4. PaymentProcessorで支払処理を実行
5. 成功時は注文完了ページへリダイレクト
6. エラー時は注文確認ページに戻る

**関連システム・外部連携**：支払ゲートウェイ（PayPal、Stripe等）、注文管理システム、在庫管理システム、メール送信システム

**権限による制御**：ログイン済み顧客のみが実行可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | 注文確認ページ | 遷移元 | 注文処理と支払い実行（CheckoutController::order） |
| 11 | 注文完了ページ | 遷移先 | 注文完了後のサンクスページ表示 |
| 22 | 注文編集ページ | エラー時遷移先 | 支払失敗時の再試行画面 |

## 機能種別

CRUD操作（Create）/ トランザクション処理 / 外部連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tos | bool | Yes | 利用規約同意 | チェック必須 |
| revocation | bool | 条件付き | 撤回権同意（デジタル商品） | デジタル商品がある場合必須 |
| customerComment | string | No | 顧客コメント | - |
| affiliateCode | string | No | アフィリエイトコード | セッションから取得 |
| campaignCode | string | No | キャンペーンコード | セッションから取得 |

### 入力データソース

- POSTリクエストボディ: フォームデータ
- SalesChannelContext: 顧客情報、支払/配送設定
- Session: アフィリエイト/キャンペーンコード
- Cart: 注文対象のカートデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| redirect | RedirectResponse | 成功時は注文完了ページ、エラー時は注文確認/編集ページへリダイレクト |
| orderId | string | 作成された注文ID |

### 出力先

- HTTPリダイレクトレスポンス
- 注文データ: `order` テーブル
- 注文明細: `order_line_item` テーブル
- 支払トランザクション: `order_transaction` テーブル

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ POSTメソッドで /checkout/order にアクセス
2. 顧客認証チェック
   └─ 未ログインの場合は登録ページへリダイレクト
3. アフィリエイトトラッキング追加
   └─ セッションからアフィリエイト/キャンペーンコードを取得しDataBagに追加
4. 注文作成
   └─ OrderService::createOrder() を呼び出し
   └─ 注文バリデーション実行
   └─ カートから注文データを生成
5. 支払処理
   └─ PaymentProcessor::pay() を呼び出し
   └─ 支払方法に応じた処理（即時決済/リダイレクト/後払い等）
6. レスポンス返却
   └─ 支払ゲートウェイからのレスポンスまたは完了ページへリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[開始: order] --> B{顧客ログイン済み?}
    B -->|No| C[登録ページへリダイレクト]
    B -->|Yes| D[アフィリエイトトラッキング追加]
    D --> E[OrderService::createOrder]
    E --> F{バリデーションOK?}
    F -->|No| G[注文確認ページへフォワード]
    F -->|Yes| H{カートエラー?}
    H -->|Yes| G
    H -->|No| I{支払エラー?}
    I -->|Yes| J[注文完了ページへ（失敗フラグ付き）]
    I -->|No| K[PaymentProcessor::pay]
    K --> L{支払成功?}
    L -->|No| J
    L -->|Yes| M{リダイレクト必要?}
    M -->|Yes| N[外部支払ページへリダイレクト]
    M -->|No| O[注文完了ページへリダイレクト]
    C --> P[終了]
    G --> P
    J --> P
    N --> P
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-48-01 | ログイン必須 | 注文処理にはログインが必要 | 常時 |
| BR-48-02 | 利用規約同意 | 利用規約への同意が必要 | 常時 |
| BR-48-03 | 撤回権同意 | デジタル商品購入時は撤回権への同意が必要 | デジタル商品存在時 |
| BR-48-04 | 支払方法有効性 | 選択された支払方法が有効である必要がある | 常時 |
| BR-48-05 | 在庫確認 | 注文確定時に在庫を再確認 | 物理商品存在時 |

### 計算ロジック

注文作成時に以下が確定される：
- 注文番号（自動採番）
- 注文金額（カートから転記）
- 税額計算
- 配送料確定
- プロモーション割引確定

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 注文作成 | order | INSERT | 注文ヘッダーの作成 |
| 明細作成 | order_line_item | INSERT | 注文明細の作成 |
| 住所コピー | order_address | INSERT | 配送先/請求先住所のコピー |
| 支払トランザクション | order_transaction | INSERT | 支払トランザクションの作成 |
| 配送情報 | order_delivery | INSERT | 配送情報の作成 |
| カート削除 | cart | DELETE | 注文完了後のカート削除 |

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

#### order

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | UUID | 注文ID |
| INSERT | order_number | 自動採番 | 注文番号 |
| INSERT | price | カートから転記 | 注文金額 |
| INSERT | state_id | 初期状態 | 注文ステータス |
| INSERT | customer_comment | リクエストから | 顧客コメント |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 認証エラー | 顧客がログインしていない | 登録ページへリダイレクト |
| ConstraintViolationException | バリデーションエラー | 入力データが無効 | 注文確認ページへフォワード |
| InvalidCartException | 業務エラー | カートが無効 | カートエラーを表示 |
| EmptyCartException | 業務エラー | カートが空 | カートエラーを表示 |
| PaymentException | 支払エラー | 支払処理失敗 | 注文編集ページへ遷移 |
| IllegalTransitionException | ステータスエラー | ステータス遷移不可 | 注文完了ページ（失敗フラグ） |

### リトライ仕様

支払失敗時は注文編集ページから支払方法を変更して再試行可能。

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

注文作成と支払トランザクション作成は単一トランザクション内で実行。支払ゲートウェイへの通信は別トランザクション。支払失敗時も注文レコードは保持され、後から支払再試行が可能。

## パフォーマンス要件

- レスポンス時間: 5000ms以内（外部支払ゲートウェイ依存）
- Profilerによるトレース: `checkout-order`, `handle-payment` として計測

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

- ログイン認証必須
- CSRFトークン検証
- 支払情報の暗号化
- PCI DSS準拠（支払処理）
- 二重注文防止

## 備考

- 外部支払ゲートウェイ使用時は、一度外部サイトにリダイレクトされ、完了後に戻ってくる
- アフィリエイトコードは注文に紐付けられ、後からアフィリエイト報酬計算に使用される

---

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

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

### 推奨読解順序

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

処理の起点となるコントローラーを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CheckoutController.php | `src/Storefront/Controller/CheckoutController.php` | orderメソッドがエントリーポイント |

**主要処理フロー**:
1. **209-253行目**: orderメソッド全体
2. **217-218行目**: 顧客ログインチェック
3. **222行目**: アフィリエイトトラッキング追加
4. **224行目**: OrderService::createOrder呼び出し（Profiler::traceでラップ）
5. **225-241行目**: 各種例外ハンドリング
6. **244行目**: finishUrlとerrorUrlの生成
7. **247行目**: PaymentProcessor::pay呼び出し
8. **249行目**: レスポンス返却

#### Step 2: 注文サービスを理解する

注文作成の詳細処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | OrderService.php | `src/Core/Checkout/Order/SalesChannel/OrderService.php` | createOrderメソッド |

**主要処理フロー**:
- **69-86行目**: createOrder()メソッド
- **71行目**: カート取得
- **73-78行目**: デジタル商品チェック
- **81行目**: 注文データバリデーション
- **83行目**: カートバリデーション
- **85行目**: CartService::orderで注文確定

#### Step 3: 支払処理を理解する

支払処理の流れを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PaymentProcessor.php | `src/Core/Checkout/Payment/PaymentProcessor.php` | payメソッド |

**読解のコツ**: PaymentProcessorは支払方法に応じたハンドラーを呼び出し、必要に応じて外部ゲートウェイへのリダイレクトを処理する。

#### Step 4: アフィリエイトトラッキングを理解する

アフィリエイト情報の処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | CheckoutController.php | `src/Storefront/Controller/CheckoutController.php` | addAffiliateTrackingメソッド |

**主要処理フロー**:
- **310-321行目**: addAffiliateTracking()メソッド
- **312-313行目**: セッションからアフィリエイト/キャンペーンコード取得
- **314-320行目**: DataBagに追加

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

```
CheckoutController::order()
    │
    ├─ context->getCustomer() - ログインチェック
    │
    ├─ addAffiliateTracking() - アフィリエイト情報追加
    │      │
    │      └─ session->get(AFFILIATE_CODE_KEY/CAMPAIGN_CODE_KEY)
    │
    ├─ Profiler::trace('checkout-order')
    │      │
    │      └─ OrderService::createOrder()
    │             │
    │             ├─ CartService::getCart() - カート取得
    │             │
    │             ├─ デジタル商品チェック
    │             │
    │             ├─ validateOrderData() - バリデーション
    │             │
    │             ├─ validateCart() - カートバリデーション
    │             │
    │             └─ CartService::order() - 注文確定
    │                    │
    │                    └─ CartOrderRoute::order()
    │
    ├─ Profiler::trace('handle-payment')
    │      │
    │      └─ PaymentProcessor::pay()
    │             │
    │             ├─ 支払方法ハンドラー取得
    │             │
    │             └─ 支払処理実行
    │
    └─ RedirectResponse - 完了ページまたはエラーページへ
```

### データフロー図

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

RequestDataBag ─────────▶ CheckoutController              ───▶ RedirectResponse
  │                              │                                    │
  ├─ tos                         ▼                                    │
  │                      ログインチェック                              │
  ├─ revocation                  │                                    │
  │                              ▼                                    │
  └─ customerComment     addAffiliateTracking()                       │
        │                        │                                    │
        │                        ▼                                    │
        │                OrderService::createOrder()                  │
        │                        │                                    │
        │                        ▼                                    │
Cart ─────────────────▶ CartService::order()                          │
        │                        │                                    │
        │                        ▼                                    │
        │                order/order_line_item INSERT                 │
        │                        │                                    │
        │                        ▼                                    │
        │                PaymentProcessor::pay()                      │
        │                        │                                    │
        │                        ▼                                    ▼
        │                order_transaction INSERT         ───▶ finishPage
        │                        │                                    │
        │                        ▼                                    │
        │                外部支払ゲートウェイ              ───▶ 外部リダイレクト
        │
        ▼
Cart DELETE
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CheckoutController.php | `src/Storefront/Controller/CheckoutController.php` | コントローラー | HTTPリクエスト処理 |
| OrderService.php | `src/Core/Checkout/Order/SalesChannel/OrderService.php` | サービス | 注文作成ロジック |
| CartService.php | `src/Core/Checkout/Cart/SalesChannel/CartService.php` | サービス | カートから注文への変換 |
| CartOrderRoute.php | `src/Core/Checkout/Cart/SalesChannel/CartOrderRoute.php` | ルート | 注文API実装 |
| PaymentProcessor.php | `src/Core/Checkout/Payment/PaymentProcessor.php` | サービス | 支払処理 |
| AffiliateTrackingListener.php | `src/Storefront/Framework/AffiliateTracking/AffiliateTrackingListener.php` | リスナー | アフィリエイトトラッキング |
| OrderValidationFactory.php | `src/Core/Checkout/Order/Validation/OrderValidationFactory.php` | ファクトリ | バリデーション定義 |
