# 通知設計書 33-Order Transaction State (Chargeback)

## 概要

本ドキュメントは、Shopwareにおける注文トランザクションでチャージバック（返金請求）が発生した際に送信されるメール通知の設計仕様を定義する。

### 本通知の処理概要

本通知は、注文の決済でチャージバックが発生した際に顧客へ送信されるメール通知である。クレジットカード決済等において、顧客または金融機関からの異議申し立てにより決済が取り消された状態を通知する。

**業務上の目的・背景**：チャージバックは決済処理において重大なイベントであり、顧客に対して決済状態の変更を通知することは、透明性の確保と信頼関係の維持に不可欠である。また、不正利用が疑われる場合の早期対応や、正当な取引の場合の再決済手続きへの誘導にも役立つ。ショップ運営者にとっては、チャージバックの発生を顧客に通知することで、問題解決への協力を得やすくなる。

**通知の送信タイミング**：注文トランザクションの状態がチャージバック（chargeback）に遷移した際に、Flowビルダーで設定されたメール送信アクションがトリガーされ、本通知が送信される。具体的には `state_machine.order_transaction.state_changed` イベントが発火し、`OrderStateChangeEventListener` が処理を行う。

**通知の受信者**：注文を行った顧客のメールアドレス（`order.orderCustomer.email`）宛に送信される。Flowビルダーの設定により、管理者やカスタムの受信者を追加することも可能。チャージバックの性質上、管理者への通知も推奨される。

**通知内容の概要**：顧客の敬称・氏名、注文番号、注文日時、新しい決済状態（チャージバック）、注文詳細確認用のURLリンクが含まれる。「Chargeback for your order with {{ salesChannel.name }}」という件名で送信される。

**期待されるアクション**：顧客は通知を受け取り、チャージバックが発生したことを確認する。身に覚えのないチャージバックの場合や、再決済を希望する場合は、ショップに連絡して対応を協議することが期待される。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（Flow経由） |
| 優先度 | 高（チャージバックは重要なイベント） |
| リトライ | メール送信サービスの設定に依存 |

### 送信先決定ロジック

1. デフォルトでは注文顧客のメールアドレス（`MailRecipientStruct`）が使用される
2. Flowビルダーの設定で `recipient.type` により以下の変更が可能:
   - `default`: 注文顧客のメールアドレス
   - `admin`: システム管理者全員
   - `custom`: カスタム指定のメールアドレス
3. チャージバックの重要性から、管理者への同時通知を設定することを推奨

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | 販売チャネル設定による |
| 送信元名称 | `{{ salesChannel.name }}` |
| 件名（英語） | Chargeback for your order with {{ salesChannel.name }} |
| 件名（ドイツ語） | Rückbuchung für Ihre Bestellung bei {{ salesChannel.name }} |
| 形式 | HTML/テキスト両対応 |

### 本文テンプレート

```html
<div style="font-family:arial; font-size:12px;">
    <br/>
    <p>
        {% if order.orderCustomer.salutation %}{{ order.orderCustomer.salutation.translated.letterName ~ ' ' }}{% endif %}{{ order.orderCustomer.firstName }} {{ order.orderCustomer.lastName }},<br/>
        <br/>
        the status of your order at {{ salesChannel.translated.name }} (Number: {{ order.orderNumber }}) on {{ order.orderDateTime|format_datetime('medium', 'short', locale='en-GB') }} has changed.<br/>
        <strong>The new status is as follows: {{ order.transactions.first.stateMachineState.translated.name }}.</strong><br/>
        <br/>
        You can check the current status of your order on our website under "My account" - "My orders" anytime: {{ rawUrl('frontend.account.order.single.page', { 'deepLinkCode': order.deepLinkCode }, salesChannel.domains|first.url) }}
        </br>
        However, in case you have purchased without a registration or a customer account, you do not have this option.
        <br><br>
        {% if a11yDocuments %}
            For better accessibility we also provide an HTML version of the documents here:<br><br>
            {% for a11y in a11yDocuments %}
                {% set documentLink = rawUrl('frontend.account.order.single.document.a11y', {...}, salesChannel.domains|first.url)%}
                - <a href="{{ documentLink }}" target="_blank">{{ documentLink }}</a> <br>
            {% endfor %}<br>
            For data protection reasons the HTML version requires a login. <br><br>
            In case of a guest order, you can use your email address and postal code of the billing address.<br>
        {% endif %}
    </p>
</div>
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 状態変更通知には添付ファイルは含まれない |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| order | 注文エンティティ | order テーブル | Yes |
| order.orderNumber | 注文番号 | order.order_number | Yes |
| order.orderDateTime | 注文日時 | order.order_date_time | Yes |
| order.orderCustomer | 注文顧客情報 | order_customer テーブル | Yes |
| order.orderCustomer.salutation | 敬称 | salutation テーブル | No |
| order.orderCustomer.firstName | 名 | order_customer.first_name | Yes |
| order.orderCustomer.lastName | 姓 | order_customer.last_name | Yes |
| order.transactions.first.stateMachineState | 決済状態 | state_machine_state テーブル | Yes |
| order.deepLinkCode | ディープリンクコード | order.deep_link_code | Yes |
| salesChannel | 販売チャネル | sales_channel テーブル | Yes |
| salesChannel.name | 販売チャネル名 | sales_channel_translation.name | Yes |
| previousState | 変更前の状態 | state_machine_state テーブル | No |
| newState | 変更後の状態 | state_machine_state テーブル | No |
| a11yDocuments | アクセシビリティドキュメント | 動的生成 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 状態変更 | state_machine.order_transaction.state_changed | 状態がchargebackに遷移 | OrderTransactionStateHandlerのchargebackメソッドで状態変更時 |
| Flow | state_enter.order_transaction.state.chargeback | Flowビルダーで設定 | Flowビルダーでメール送信アクションが設定されている場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| メールテンプレート未設定 | 対応するメールテンプレートが存在しない場合 |
| Flow未設定 | Flowビルダーでメール送信アクションが設定されていない場合 |
| MailSendSubscriberConfig.skip | 拡張機能によりスキップが指定されている場合 |
| 受信者なし | 有効な受信者メールアドレスが取得できない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[チャージバック発生/決済状態がchargebackに遷移] --> B[StateMachineStateChangeEvent発火]
    B --> C[OrderStateChangeEventListener.onOrderTransactionStateChange]
    C --> D[OrderStateMachineStateChangeEventディスパッチ]
    D --> E[Flowビルダーがイベントを検知]
    E --> F{SendMailActionが設定されている?}
    F -->|Yes| G[SendMailAction.handleFlow]
    F -->|No| H[処理終了]
    G --> I[メールテンプレート取得]
    I --> J{テンプレート存在?}
    J -->|Yes| K[受信者決定]
    J -->|No| H
    K --> L{受信者あり?}
    L -->|Yes| M[テンプレート変数展開]
    L -->|No| H
    M --> N[AbstractMailService.send]
    N --> O{送信結果}
    O -->|成功| P[処理完了]
    O -->|失敗| Q[エラーログ記録]
    Q --> P
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| order | 注文情報取得 | 主要な注文データ |
| order_customer | 顧客情報取得 | 受信者情報 |
| order_transaction | トランザクション情報 | 決済状態 |
| state_machine_state | 状態マシン状態 | 状態名取得 |
| sales_channel | 販売チャネル | 送信元情報 |
| mail_template | メールテンプレート | テンプレート本文 |
| mail_template_type | テンプレートタイプ | テンプレート種別 |

### テーブル別参照項目詳細

#### order

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| order_number | 注文番号表示 | order.id = :orderId |
| order_date_time | 注文日時表示 | 同上 |
| deep_link_code | 注文詳細リンク生成 | 同上 |

#### mail_template

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | テンプレート識別 | mail_template_type.technical_name = 'order_transaction.state.chargeback' |
| content_html | HTML本文 | 同上 |
| content_plain | テキスト本文 | 同上 |
| subject | 件名 | 同上 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| mail_template_type | UPDATE | templateDataの更新（設定による） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | SMTPサーバー接続エラー等 | エラーログ記録、例外はキャッチされ処理継続 |
| テンプレートエラー | Twigテンプレートの変数エラー | エラーログ記録 |
| 宛先不正 | メールアドレス形式不正 | 送信スキップ |
| テンプレート未存在 | mailTemplateIdに対応するテンプレートなし | 処理終了（エラーなし） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | メールサービス設定による |
| リトライ間隔 | メールサービス設定による |
| リトライ対象エラー | 一時的な送信エラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | メールサービス設定による |
| 1日あたり上限 | メールサービス設定による |

### 配信時間帯

特に制限なし。状態変更時に即座に送信される。

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

- チャージバックは金銭的影響が大きいため、通知の確実な配信が重要
- 顧客メールアドレスは注文データから取得し、外部への漏洩を防止
- ディープリンクコードを使用した注文詳細アクセスはログイン不要だが、推測困難なランダム文字列を使用
- チャージバック通知は不正利用検知の一環としても機能

## 備考

- 本テンプレートタイプの技術名は `order_transaction.state.chargeback`
- MailTemplateTypesクラスで `MAILTYPE_STATE_ENTER_ORDER_TRANSACTION_STATE_CHARGEBACK` として定義
- Migration1688106315AddMissingTransactionMailTemplatesで初期テンプレートが追加された
- OrderTransactionStatesクラスで `STATE_CHARGEBACK = 'chargeback'` として定義
- OrderTransactionStateHandlerクラスにchargeback()メソッドが実装されている

---

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

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

### 推奨読解順序

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

まず、決済状態の定義とメールテンプレートタイプの定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | OrderTransactionStates.php | `src/Core/Checkout/Order/Aggregate/OrderTransaction/OrderTransactionStates.php` | 決済状態の定数定義（STATE_CHARGEBACK = 'chargeback'、行21） |
| 1-2 | MailTemplateTypes.php | `src/Core/Content/MailTemplate/MailTemplateTypes.php` | メールテンプレートタイプの定数（行80: MAILTYPE_STATE_ENTER_ORDER_TRANSACTION_STATE_CHARGEBACK） |

**読解のコツ**: チャージバックはSTATE_CHARGEBACKとして定義されている。

#### Step 2: 状態遷移処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | OrderTransactionStateHandler.php | `src/Core/Checkout/Order/Aggregate/OrderTransaction/OrderTransactionStateHandler.php` | chargeback()メソッドの実装 |

**主要処理フロー**:
- **行245-256**: chargeback()メソッドでchargeback状態への遷移を実行

#### Step 3: メールテンプレート追加マイグレーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Migration1688106315AddMissingTransactionMailTemplates.php | `src/Core/Migration/V6_5/Migration1688106315AddMissingTransactionMailTemplates.php` | テンプレート追加処理 |

**主要処理フロー**:
- **行25**: CHARGEBACK_TYPEの定義
- **行70-93**: chargebackテンプレートの定義（翻訳含む）

#### Step 4: イベントリスナーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | OrderStateChangeEventListener.php | `src/Core/Checkout/Order/Listener/OrderStateChangeEventListener.php` | イベント購読とディスパッチ |

**主要処理フロー**:
- **行53**: state_machine.order_transaction.state_changedの購読
- **行82-102**: onOrderTransactionStateChange()でトランザクション状態変更を処理

#### Step 5: メール送信アクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | SendMailAction.php | `src/Core/Content/Flow/Dispatching/Action/SendMailAction.php` | Flowからのメール送信処理 |

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

```
OrderTransactionStateHandler::chargeback()
    │
    └─ StateMachineRegistry::transition()
           │
           ├─ StateMachineStateChangeEvent発火
           │      │
           │      └─ OrderStateChangeEventListener::onOrderTransactionStateChange()
           │              │
           │              └─ EventDispatcher::dispatch(OrderStateMachineStateChangeEvent)
           │                      │
           │                      └─ FlowDispatcher（Flowビルダー）
           │                              │
           │                              └─ SendMailAction::handleFlow()
           │                                      │
           │                                      └─ AbstractMailService::send()
```

### データフロー図

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

チャージバック発生    ───▶ OrderTransactionStateHandler  ───▶ state_machine_state
(外部決済システム)         ::chargeback()                     (新状態: chargeback)
                              │
                              ▼
                     StateMachineStateChangeEvent
                              │
                              ▼
                     OrderStateChangeEventListener    ───▶ OrderStateMachineStateChangeEvent
                              │
                              ▼
                     FlowDispatcher                   ───▶ SendMailAction実行
                              │
                              ▼
order (注文データ)    ───▶ SendMailAction              ───▶ メール送信
mail_template             (テンプレート展開)                 (SMTP)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| OrderTransactionStates.php | `src/Core/Checkout/Order/Aggregate/OrderTransaction/OrderTransactionStates.php` | ソース | 決済状態定数定義 |
| OrderTransactionStateHandler.php | `src/Core/Checkout/Order/Aggregate/OrderTransaction/OrderTransactionStateHandler.php` | ソース | 状態遷移ハンドラー（chargeback()メソッド） |
| OrderStateChangeEventListener.php | `src/Core/Checkout/Order/Listener/OrderStateChangeEventListener.php` | ソース | 状態変更イベントリスナー |
| SendMailAction.php | `src/Core/Content/Flow/Dispatching/Action/SendMailAction.php` | ソース | メール送信アクション |
| MailTemplateTypes.php | `src/Core/Content/MailTemplate/MailTemplateTypes.php` | ソース | テンプレートタイプ定義 |
| Migration1688106315AddMissingTransactionMailTemplates.php | `src/Core/Migration/V6_5/Migration1688106315AddMissingTransactionMailTemplates.php` | マイグレーション | テンプレート追加 |
| en-html.html.twig | `src/Core/Migration/Fixtures/mails/order_transaction.state.chargeback/en-html.html.twig` | テンプレート | 英語HTMLテンプレート |
| en-plain.html.twig | `src/Core/Migration/Fixtures/mails/order_transaction.state.chargeback/en-plain.html.twig` | テンプレート | 英語テキストテンプレート |
| de-html.html.twig | `src/Core/Migration/Fixtures/mails/order_transaction.state.chargeback/de-html.html.twig` | テンプレート | ドイツ語HTMLテンプレート |
| de-plain.html.twig | `src/Core/Migration/Fixtures/mails/order_transaction.state.chargeback/de-plain.html.twig` | テンプレート | ドイツ語テキストテンプレート |
