# 画面設計書 45-プロモーション管理

## 概要

本ドキュメントは、Shopware 6 Administration（管理画面）における「プロモーション管理」画面の設計書です。この画面は割引・クーポンの設定を行う販促キャンペーン管理機能を提供します。

### 本画面の処理概要

**業務上の目的・背景**：ECサイトの売上向上のため、様々なプロモーション施策（割引、クーポン、送料無料など）を実施することは重要なマーケティング活動です。本画面は、プロモーションの作成、条件設定、割引ルールの定義、クーポンコードの管理など、包括的なプロモーション管理機能を提供します。複雑な条件に基づく割引ルールを直感的なUIで設定できます。

**画面へのアクセス方法**：管理画面にログイン後、左側メニューの「マーケティング」→「プロモーション」をクリックすることでアクセスできます。URLパスは `/admin#/sw/promotion/v2/index` となります。`promotion.viewer` 権限を持つユーザーのみがアクセス可能です。

**主要な操作・処理内容**：
1. プロモーション一覧の表示 - 名前、有効状態、有効期間を一覧表示
2. プロモーションの検索 - キーワード検索による絞り込み
3. プロモーションの作成 - 新規プロモーションの作成
4. プロモーションの編集 - 基本情報、条件、割引の編集
5. プロモーションの複製 - 既存プロモーションをコピーして新規作成
6. プロモーションの削除 - 未使用のプロモーションを削除
7. インライン編集 - 名前、有効状態、有効期間のインライン編集

**画面遷移**：
- 遷移元: ダッシュボード、メニュー
- 遷移先: プロモーション詳細画面（sw.promotion.v2.detail）

**権限による表示制御**：
- `promotion.viewer`: 閲覧権限 - プロモーション一覧の表示が可能
- `promotion.creator`: 作成権限 - 新規作成ボタンが表示
- `promotion.editor`: 編集権限 - インライン編集が可能
- `promotion.deleter`: 削除権限 - 削除ボタンが表示（使用回数0のもののみ）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 46 | プロモーションコード追加 | 主機能 | 割引・クーポンの設定 |

## 画面種別

一覧

## URL/ルーティング

- **パス**: `/admin#/sw/promotion/v2/index`
- **コンポーネント**: `sw-promotion-v2-list`
- **ルート名**: `sw.promotion.v2.index`
- **必要権限**: `promotion.viewer`

## 入出力項目

| 項目名 | 種別 | 型 | 必須 | 説明 |
|--------|------|-----|------|------|
| term | 入力 | string | - | 検索キーワード |
| page | 入力 | number | - | ページ番号 |
| limit | 入力 | number | - | 1ページあたりの表示件数 |
| sortBy | 入力 | string | - | ソート対象カラム（デフォルト: createdAt） |
| sortDirection | 入力 | string | - | ソート方向（デフォルト: DESC） |

## 表示項目

| 項目名 | カラム名 | 説明 | 編集可否 |
|--------|----------|------|----------|
| 名前 | name | プロモーション名（詳細へのリンク） | string（インライン編集可） |
| 有効 | active | 有効/無効状態 | boolean（インライン編集可） |
| 開始日時 | validFrom | プロモーション開始日時 | date（インライン編集可） |
| 終了日時 | validUntil | プロモーション終了日時 | date（インライン編集可） |

## イベント仕様

### 1-ページ読み込み

画面初期表示時にプロモーション一覧を取得する。

**処理フロー**:
1. `getList()` メソッドが呼び出される
2. `promotionCriteria` を構築（ページネーション、ソート、検索条件）
3. `promotionRepository.search()` でプロモーションデータを取得
4. 取得結果を `promotions` データに格納し表示

### 2-検索実行

検索ボックスにキーワードを入力し検索を実行。

**処理フロー**:
1. 検索キーワードが `term` にセット
2. `promotionCriteria` が再構築され `setTerm()` で検索条件追加
3. `getList()` が実行され検索結果を表示

### 3-プロモーション作成

新規作成ボタンをクリック。

**処理フロー**:
1. `$router.push({ name: 'sw.promotion.v2.create.base' })` で作成画面へ遷移

### 4-プロモーション編集

プロモーション名または編集ボタンをクリック。

**処理フロー**:
1. 選択されたプロモーションのIDを取得
2. `$router.push({ name: 'sw.promotion.v2.detail', params: { id } })` で詳細画面へ遷移

### 5-プロモーション複製（onDuplicatePromotion）

コンテキストメニューの複製をクリック。

**処理フロー**:
1. 複製時の上書き設定を構築：
   - 名前: 元の名前 + " Copy"
   - code: null（コードは複製しない）
   - useCodes: false
   - useIndividualCodes: false
   - individualCodePattern: ''
   - active: false（無効状態で作成）
   - orderCount: 0
2. `promotionRepository.clone()` でプロモーションを複製
3. 成功時、作成したプロモーションの詳細画面へ遷移
4. 複製完了の通知を表示

### 6-プロモーション削除

削除ボタンをクリック。

**処理フロー**:
1. `orderCount > 0` の場合、削除不可（使用済みプロモーション）
2. 削除確認モーダルを表示
3. 確定時、`promotionRepository.delete()` を実行
4. 成功後、リストを再取得

### 7-インライン編集

一覧画面で直接値を編集。

**処理フロー**:
1. 編集モードに入る
2. name, active, validFrom, validUntil を編集
3. 保存時、`promotionRepository.save()` で更新

### 8-言語切替（onChangeLanguage）

管理画面の言語を変更。

**処理フロー**:
1. `getList()` を再実行して翻訳を更新

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| プロモーション一覧取得 | promotion | SELECT | プロモーションデータの取得 |
| インライン編集保存 | promotion | UPDATE | name, active, valid_from, valid_until の更新 |
| プロモーション複製 | promotion, promotion_discount, promotion_individual_code 等 | INSERT | 全関連データの複製 |
| プロモーション削除 | promotion | DELETE | プロモーションの削除 |

### テーブル別更新項目詳細

#### promotion

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | ページネーション、ソート条件に基づく | |
| UPDATE | name | 入力値 | インライン編集時 |
| UPDATE | active | true/false | インライン編集時 |
| UPDATE | valid_from | 日時値 | インライン編集時 |
| UPDATE | valid_until | 日時値 | インライン編集時 |
| INSERT | * | 元プロモーションの値（一部上書き） | 複製時 |
| DELETE | - | id指定 | orderCount=0の場合のみ |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| sw-promotion-v2.list.duplicatePromotionInfo | 情報 | プロモーションを複製しました | 複製成功時 |
| sw-promotion-v2.list.deleteDisabledToolTip | 警告 | 使用済みのため削除できません | 削除不可時のツールチップ |
| sw-privileges.tooltip.warning | 警告 | 権限がありません | 権限不足時 |

## 例外処理

| 例外ケース | 処理内容 |
|-----------|---------|
| 検索結果0件 | 空状態のメッセージを表示 |
| 使用済みプロモーションの削除試行 | 削除ボタンを無効化、ツールチップで理由を表示 |
| 複製失敗 | エラーをスロー、ローディング解除 |
| 権限不足 | 作成ボタンを無効化、ツールチップで権限不足を通知 |

## 備考

- プロモーションが注文で使用されると `orderCount` がインクリメントされ、削除不可になる
- 複製時、クーポンコード関連の設定はリセットされる（重複防止）
- プロモーションモジュールは `sw-promotion-v2` として実装（旧バージョンとの区別）
- 有効期間は validFrom/validUntil で管理され、範囲外は自動的に無効化される
- 一括削除は `orderCount > 0` のものが含まれていると実行不可（`allowBulkDelete`）

---

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

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

### 推奨読解順序

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

プロモーションエンティティの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PromotionDefinition | `src/Core/Checkout/Promotion/PromotionDefinition.php` | プロモーションエンティティの定義 |
| 1-2 | PromotionDiscountDefinition | `src/Core/Checkout/Promotion/Aggregate/PromotionDiscount/PromotionDiscountDefinition.php` | 割引設定 |

**読解のコツ**: Promotionはdiscounts（割引設定）、individualCodes（個別コード）、salesChannels（販売チャネル）など多くの関連エンティティを持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/index.js` | モジュール登録、ルート定義 |

**主要処理フロー**:
1. **63-180行**: `Module.register('sw-promotion-v2', ...)` でモジュールを登録
2. **75-88行**: `routes.index` で一覧画面のルート定義
3. **158-176行**: ナビゲーション定義

#### Step 3: 一覧画面コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sw-promotion-v2-list/index.js | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/page/sw-promotion-v2-list/index.js` | Vue.jsコンポーネントの定義 |

**主要処理フロー**:
- **24-33行**: `data()` - コンポーネントの状態定義
- **47-51行**: `promotionCriteria` - 検索条件の構築
- **76-92行**: `getList()` - プロモーションデータ取得処理
- **99-131行**: `getPromotionColumns()` - テーブルカラム定義
- **137-171行**: `onDuplicatePromotion()` - 複製処理

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

```
sw-promotion-v2-list (Vue Component)
    │
    ├─ getList()
    │      ├─ addQueryScores()
    │      └─ promotionRepository.search(criteria)
    │             └─ Shopware API (POST /api/search/promotion)
    │
    ├─ onDuplicatePromotion(promotion)
    │      ├─ behavior設定構築
    │      └─ promotionRepository.clone(id, behavior)
    │             └─ Shopware API (POST /api/_action/clone/promotion/{id})
    │
    └─ 削除処理
           └─ promotionRepository.delete(id)
                  └─ Shopware API (DELETE /api/promotion/{id})
```

### データフロー図

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

検索キーワード ─────────┐
                        │
ソート設定 ─────────────┼──▶ sw-promotion-v2-list Component
                        │         │
ページング ─────────────┘         ├──▶ promotionCriteria構築
                                  │         │
                                  │         ▼
                                  │    Criteria API
                                  │         │
                                  │         ▼
                                  │    promotionRepository.search()
                                  │         │
                                  │         ▼
                                  │    Shopware API
                                  │         │
                                  │         ▼
                                  └──▶ promotions データ ──▶ 一覧表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/index.js` | ソース | モジュール定義 |
| sw-promotion-v2-list/index.js | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/page/sw-promotion-v2-list/index.js` | ソース | 一覧画面コンポーネント |
| sw-promotion-v2-list.html.twig | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/page/sw-promotion-v2-list/sw-promotion-v2-list.html.twig` | テンプレート | 画面テンプレート |
| promotion-code.api.service.js | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/service/promotion-code.api.service.js` | ソース | コード生成API |
| acl/index.js | `src/Administration/Resources/app/administration/src/module/sw-promotion-v2/acl/index.js` | ソース | 権限定義 |
| PromotionDefinition.php | `src/Core/Checkout/Promotion/PromotionDefinition.php` | ソース | エンティティ定義 |
