# 機能設計書 49-注文完了ページ

## 概要

本ドキュメントは、注文完了後のサンクスページを表示する機能の設計を定義するものである。

### 本機能の処理概要

注文処理が正常に完了した後、顧客に注文完了を通知し、注文内容を表示するページを提供する機能である。

**業務上の目的・背景**：注文完了を顧客に明確に伝え、注文内容を確認させることで、顧客に安心感を与える。また、ゲスト顧客の場合は注文後に自動ログアウトを行い、セキュリティを確保する。このページは顧客体験の最終段階であり、購入への感謝を伝え、次のアクション（会員登録、他の商品閲覧など）への誘導を行う重要なタッチポイントである。

**機能の利用シーン**：支払処理が完了し、注文が確定した後に自動的にリダイレクトされて表示される。外部支払ゲートウェイを使用した場合は、支払完了後のコールバックで遷移してくる。

**主要な処理内容**：
1. 顧客のログイン状態を確認
2. 注文IDを取得して注文データを読み込み
3. 支払失敗フラグのチェック
4. ゲスト顧客の自動ログアウト処理
5. ページデータを構築してテンプレートをレンダリング

**関連システム・外部連携**：注文管理システム、メール送信システム（注文確認メール）

**権限による制御**：ログイン済み顧客のみがアクセス可能。注文者本人の注文のみ閲覧可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | 注文完了ページ | 主画面 | 注文完了後のサンクスページ表示（CheckoutController::finishPage） |
| 10 | 注文確認ページ | 遷移元 | 注文確定後の遷移元 |

## 機能種別

画面表示 / データ取得

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| orderId | string | Yes | 注文ID | UUID形式、存在すること |
| changedPayment | bool | No | 支払方法変更フラグ | - |
| paymentFailed | bool | No | 支払失敗フラグ | - |

### 入力データソース

- クエリパラメータ: `orderId`, `changedPayment`, `paymentFailed`
- SalesChannelContext: 顧客情報
- Request: HTTPリクエストオブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| page | CheckoutFinishPage | ページデータオブジェクト |
| page.order | OrderEntity | 注文データ |
| page.changedPayment | bool | 支払方法変更フラグ |
| page.paymentFailed | bool | 支払失敗フラグ |
| page.logoutCustomer | bool | ゲスト自動ログアウトフラグ |

### 出力先

- HTMLレスポンス（Twigテンプレートをレンダリング）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ GETメソッドで /checkout/finish?orderId=xxx にアクセス
2. 顧客認証チェック
   └─ 未ログインの場合は登録ページへリダイレクト
3. ページデータ読み込み
   └─ CheckoutFinishPageLoader::load() を呼び出し
4. 注文データ取得
   └─ OrderRouteから注文データを取得
   └─ 注文者本人の注文であることを確認
5. 支払失敗チェック
   └─ 支払失敗時は注文編集ページへリダイレクト
6. ゲストログアウト判定
   └─ ゲスト顧客かつ設定が有効な場合はログアウト処理
7. フックイベント発火
   └─ CheckoutFinishPageLoadedHook を発火
8. レスポンス返却
   └─ テンプレートをレンダリングして返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始: finishPage] --> B{顧客ログイン済み?}
    B -->|No| C[登録ページへリダイレクト]
    B -->|Yes| D[CheckoutFinishPageLoader::load]
    D --> E{注文データ取得成功?}
    E -->|No| F[カートページへリダイレクト]
    E -->|Yes| G[CheckoutFinishPageLoadedHook発火]
    G --> H{支払失敗?}
    H -->|Yes| I[注文編集ページへリダイレクト]
    H -->|No| J{ゲストログアウト?}
    J -->|Yes| K[LogoutRoute::logout]
    J -->|No| L[テンプレートレンダリング]
    K --> L
    C --> M[終了]
    F --> M
    I --> M
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | ログイン必須 | 注文完了ページへのアクセスにはログインが必要 | 常時 |
| BR-49-02 | 本人確認 | 注文者本人の注文のみ閲覧可能 | 常時 |
| BR-49-03 | ゲストログアウト | ゲスト顧客は設定に応じて自動ログアウト | core.cart.logoutGuestAfterCheckout設定 |
| BR-49-04 | 支払失敗リダイレクト | 支払失敗時は注文編集ページへ遷移 | paymentFailed=true時 |

### 計算ロジック

注文データ表示時に以下が計算・整形される：
- 注文の丸め設定（itemRounding, totalRounding）をコンテキストに反映
- 価格表示の通貨フォーマット

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 注文取得 | order | SELECT | 注文データと関連データを取得 |

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

#### order（読み取りのみ）

関連テーブルとして以下を含めて取得：
- `primaryOrderDelivery.shippingMethod` - 配送方法
- `primaryOrderDelivery.shippingOrderAddress` - 配送先住所
- `primaryOrderTransaction.paymentMethod` - 支払方法
- `lineItems.cover` - 商品画像
- `billingAddress` - 請求先住所

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 認証エラー | 顧客がログインしていない | 登録ページへリダイレクト |
| FRAMEWORK__MISSING_REQUEST_PARAMETER | パラメータエラー | orderIdがない | カートページへリダイレクト |
| CHECKOUT__ORDER_ORDER_NOT_FOUND | 業務エラー | 注文が見つからない | カートページへリダイレクト |

### リトライ仕様

エラー発生時はカートページまたは登録ページへリダイレクトし、最初からやり直す。

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

参照処理のみのため、特別なトランザクション制御は不要。

## パフォーマンス要件

- レスポンス時間: 1000ms以内
- Profilerによるトレース: `finish-page-order-loading` として計測

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

- ログイン認証必須
- 注文者本人確認（customerId照合）
- robots noindex設定
- キャッシュ無効化（PlatformRequest::ATTRIBUTE_NO_STORE）
- ゲストの自動ログアウト（セッションハイジャック防止）

## 備考

- 注文確認メールは別のイベントリスナーで処理される
- 外部支払からのリダイレクト時は、支払結果に応じてpaymentFailedフラグが設定される

---

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

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

### 推奨読解順序

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

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

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

**主要処理フロー**:
1. **162-207行目**: finishPageメソッド全体
2. **171-173行目**: 顧客ログインチェック
3. **176行目**: CheckoutFinishPageLoader::load呼び出し
4. **183行目**: CheckoutFinishPageLoadedHook発火
5. **185-193行目**: 支払失敗時のリダイレクト
6. **195-197行目**: ゲストログアウト処理
7. **199-200行目**: ヘッダー/フッター読み込み
8. **202-206行目**: テンプレートレンダリング

#### Step 2: ページローダーを理解する

実際のデータ取得処理を行うページローダーを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CheckoutFinishPageLoader.php | `src/Storefront/Page/Checkout/Finish/CheckoutFinishPageLoader.php` | データ取得ロジック |

**主要処理フロー**:
- **52-82行目**: load()メソッド全体
- **54-57行目**: 汎用ページローダーとメタ情報設定
- **59-61行目**: 注文データ取得（Profiler::traceでラップ）
- **63行目**: changedPaymentフラグ設定
- **65行目**: paymentFailedフラグ設定
- **67行目**: ゲストログアウトフラグ設定
- **69-71行目**: CheckoutFinishPageLoadedEvent発火
- **73-79行目**: 丸め設定のコンテキスト反映

#### Step 3: 注文データ取得を理解する

注文データの取得処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CheckoutFinishPageLoader.php | `src/Storefront/Page/Checkout/Finish/CheckoutFinishPageLoader.php` | getOrderメソッド |

**主要処理フロー**:
- **98-153行目**: getOrder()メソッド全体
- **100-103行目**: 顧客存在チェック
- **105-108行目**: orderId取得
- **110-131行目**: Criteria構築（関連データ含む）
- **133-135行目**: CheckoutFinishPageOrderCriteriaEvent発火
- **137-143行目**: OrderRoute::load呼び出し
- **146-150行目**: 注文存在チェック

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

```
CheckoutController::finishPage()
    │
    ├─ context->getCustomer() - ログインチェック
    │
    ├─ CheckoutFinishPageLoader::load()
    │      │
    │      ├─ GenericPageLoader::load() - 基本ページ情報
    │      │
    │      ├─ setMetaInformation() - SEO情報設定
    │      │
    │      ├─ Profiler::trace('finish-page-order-loading')
    │      │      │
    │      │      └─ getOrder()
    │      │             │
    │      │             ├─ Criteria構築（関連データ指定）
    │      │             │
    │      │             ├─ CheckoutFinishPageOrderCriteriaEvent発火
    │      │             │
    │      │             └─ OrderRoute::load() - 注文データ取得
    │      │
    │      ├─ setChangedPayment() - 支払方法変更フラグ
    │      │
    │      ├─ setPaymentFailed() - 支払失敗フラグ
    │      │
    │      └─ setLogoutCustomer() - ゲストログアウトフラグ
    │
    ├─ hook(CheckoutFinishPageLoadedHook)
    │
    ├─ 支払失敗チェック → 注文編集ページへリダイレクト
    │
    ├─ LogoutRoute::logout() - ゲストログアウト（条件付き）
    │
    ├─ HeaderPageletLoader::load() - ヘッダー読み込み
    │
    ├─ FooterPageletLoader::load() - フッター読み込み
    │
    └─ renderStorefront() - テンプレートレンダリング
```

### データフロー図

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

orderId ───────────────▶ CheckoutController              ───▶ HTMLレスポンス
  │                              │                                    │
  │                              ▼                                    │
  │                      ログインチェック                              │
  │                              │                                    │
  │                              ▼                                    │
  │                      CheckoutFinishPageLoader                     │
  │                              │                                    │
  │                              ▼                                    │
  │                      getOrder()                                   │
  │                              │                                    │
  │                              ▼                                    ▼
  │                      OrderRoute::load()         ───────▶ CheckoutFinishPage
  │                              │                                    │
  │                              ▼                                    ├─ order
order テーブル ────────▶ OrderEntity取得                               ├─ changedPayment
  │                              │                                    ├─ paymentFailed
  ├─ order_line_item             ▼                                    └─ logoutCustomer
  │                      フラグ設定
  ├─ order_delivery              │
  │                              ▼
  ├─ order_transaction   ゲストログアウト判定
  │                              │
  └─ order_address               ▼
                         LogoutRoute::logout() (条件付き)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CheckoutController.php | `src/Storefront/Controller/CheckoutController.php` | コントローラー | HTTPリクエスト処理 |
| CheckoutFinishPageLoader.php | `src/Storefront/Page/Checkout/Finish/CheckoutFinishPageLoader.php` | ページローダー | データ取得・構築 |
| CheckoutFinishPage.php | `src/Storefront/Page/Checkout/Finish/CheckoutFinishPage.php` | ページエンティティ | ページデータ構造 |
| AbstractOrderRoute.php | `src/Core/Checkout/Order/SalesChannel/AbstractOrderRoute.php` | ルート | 注文データ取得API |
| AbstractLogoutRoute.php | `src/Core/Checkout/Customer/SalesChannel/AbstractLogoutRoute.php` | ルート | ログアウト処理 |
| GenericPageLoaderInterface.php | `src/Storefront/Page/GenericPageLoaderInterface.php` | インターフェース | 汎用ページ読み込み |
| CheckoutFinishPageLoadedHook.php | `src/Storefront/Page/Checkout/Finish/CheckoutFinishPageLoadedHook.php` | フック | ページ読み込み後フック |
| SystemConfigService.php | `src/Core/System/SystemConfig/SystemConfigService.php` | サービス | システム設定取得 |
| index.html.twig | `src/Storefront/Resources/views/storefront/page/checkout/finish/index.html.twig` | テンプレート | 画面レンダリング |
