# 画面設計書 19-リード変換画面

## 概要

Fat Free CRM におけるリード（見込み客）を連絡先・取引先・商談に変換（コンバート）するための画面設計書である。

### 本画面の処理概要

本画面は、営業プロセスにおいてリードが商談段階に進んだ際に、リードを正式な連絡先・取引先・商談エンティティに変換するためのフォーム画面である。Ajax通信によるモーダル形式で表示される。

**業務上の目的・背景**：
リードが十分にクオリファイされ、商談の見込みがあると判断された場合、リードを連絡先（Contact）に変換し、必要に応じて取引先（Account）と商談（Opportunity）を同時に作成する。これにより、リード管理フェーズから商談管理フェーズへのスムーズな移行を実現する。変換後、元のリード情報は連絡先に引き継がれ、リードのステータスは「converted」となる。

**画面へのアクセス方法**：
1. リード詳細画面で「Convert」ボタンをクリック
2. リード一覧画面で変換アイコンをクリック
3. Ajax通信でモーダルとして表示される

**主要な操作・処理内容**：
1. 取引先の選択または新規作成
2. 担当者の選択
3. 商談情報の入力（任意）
4. 変換後のアクセス権限の設定
5. 変換実行またはキャンセル

**画面遷移**：
- 遷移元: リード詳細画面、リード一覧画面
- 遷移先（変換成功時）: 連絡先詳細画面またはリード詳細画面（更新）
- 遷移先（キャンセル時）: 遷移元画面（変更なし）

**権限による表示制御**：
- リードのアクセス権限に基づいて変換可否が決定
- 作成者または共有されたユーザーのみ変換可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | リード変換 | 主機能 | リードから連絡先・取引先・商談への変換 |
| 31 | 取引先作成 | 補助機能 | 変換時の取引先新規作成 |
| 51 | 商談作成 | 補助機能 | 変換時の商談新規作成 |
| 84 | アクセス権限管理 | 補助機能 | 変換後エンティティの権限設定 |

## 画面種別

処理

## URL/ルーティング

| HTTPメソッド | URL | アクション | 説明 |
|-------------|-----|----------|------|
| GET | /leads/:id/convert | convert | 変換フォーム表示 |
| PUT | /leads/:id/promote | promote | 変換実行 |

## 入出力項目

### 取引先セクション（Account）

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| 取引先選択/新規作成 | ラジオボタン+セレクト/テキスト | - | 既存取引先の選択または新規名を入力 |
| 担当者 | セレクトボックス | - | 取引先の担当者 |

### 商談セクション（Opportunity）- 任意

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| 商談名 | テキスト | - | 商談の名称（入力時のみ商談作成） |
| ステージ | セレクトボックス | - | 商談ステージ（Setting.opportunity_stage） |
| 成約予定日 | 日付 | - | クローズ予定日 |
| 確度 | テキスト（数値） | - | 成約確率（%） |
| 金額 | テキスト（数値） | - | 商談金額 |
| 割引 | テキスト（数値） | - | 割引金額 |

### 権限セクション（Permissions）

| 項目名 | 入力形式 | 必須 | 説明 |
|--------|---------|------|------|
| アクセス権限 | ラジオボタン | ○ | Lead/Private/Public/Shared |
| 共有ユーザー | マルチセレクト | 条件付 | Shared選択時に表示 |
| 共有グループ | マルチセレクト | 条件付 | Shared選択時に表示 |

## 表示項目

### フォームヘッダー

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| 変換対象リード名 | string | @lead.full_name |
| 変換説明テキスト | string | "Convert lead to contact" |

## イベント仕様

### 01-フォーム表示

「Convert」リンクをクリックすると、Ajax通信で変換フォームが読み込まれ、モーダルとして展開される。リードの会社名が取引先名にプリセットされる。

### 02-取引先選択/新規作成切り替え

ラジオボタンで既存取引先の選択と新規作成を切り替える。新規作成時はリードの会社名がデフォルト値として設定される。

### 03-権限オプション変更

権限ラジオボタンを変更すると、JavaScriptでaccount_accessとopportunity_accessの隠しフィールドが更新される。Shared選択時は共有先選択UIが表示される。

### 04-変換ボタン押下

「Convert Lead」ボタンをクリックすると、Ajax通信でPUTリクエストが送信される。Lead.promoteメソッドにより取引先・商談・連絡先が作成され、リードのステータスがconvertedに変更される。

### 05-キャンセル

「Cancel」リンクをクリックすると、フォームが閉じ、変換は行われない。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 変換実行 | accounts | INSERT/SELECT | 取引先新規作成または既存選択 |
| 変換実行 | contacts | INSERT | 連絡先作成（リード情報を引き継ぎ） |
| 変換実行 | opportunities | INSERT | 商談作成（商談名入力時のみ） |
| 変換実行 | leads | UPDATE | ステータスをconvertedに変更 |
| 変換実行 | addresses | INSERT | 連絡先の住所（リードから引き継ぎ） |
| 変換実行 | permissions | INSERT | 権限レコード作成 |
| 変換実行 | account_opportunities | INSERT | 取引先-商談関連（商談作成時） |
| 変換実行 | contact_opportunities | INSERT | 連絡先-商談関連（商談作成時） |
| 変換実行 | versions | INSERT | 変更履歴記録 |

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

#### leads

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | status | 'converted' | Lead.convert メソッドにより更新 |
| UPDATE | updated_at | 現在日時 | |

#### contacts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | lead_id | 元リードのID | 変換元リードとの関連 |
| INSERT | user_id | params[:account][:user_id] | |
| INSERT | assigned_to | params[:account][:assigned_to] | |
| INSERT | access | params[:access] | |
| INSERT | first_name | @lead.first_name | リードから引き継ぎ |
| INSERT | last_name | @lead.last_name | リードから引き継ぎ |
| INSERT | title | @lead.title | リードから引き継ぎ |
| INSERT | source | @lead.source | リードから引き継ぎ |
| INSERT | email | @lead.email | リードから引き継ぎ |
| INSERT | phone | @lead.phone | リードから引き継ぎ |
| INSERT | mobile | @lead.mobile | リードから引き継ぎ |
| INSERT | do_not_call | @lead.do_not_call | リードから引き継ぎ |

#### accounts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT（新規時） | name | 入力値または@lead.company | |
| INSERT（新規時） | user_id | current_user.id | |
| INSERT（新規時） | access | params[:access] | |
| SELECT（既存時） | id | params[:account][:id] | 既存取引先の選択 |

#### opportunities

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | 入力値 | 名前入力時のみ作成 |
| INSERT | stage | 入力値 | デフォルト: prospecting |
| INSERT | closes_on | 入力値 | |
| INSERT | probability | 入力値 | |
| INSERT | amount | 入力値 | |
| INSERT | discount | 入力値 | |
| INSERT | campaign_id | @lead.campaign_id | リードのキャンペーンを引き継ぎ |
| INSERT | source | @lead.source | リードのソースを引き継ぎ |

## メッセージ仕様

| メッセージ種別 | メッセージコード | 表示内容 | 表示条件 |
|--------------|----------------|---------|---------|
| 説明 | convert_lead_text | "Convert %{name} to contact" | フォーム上部に表示 |
| 説明 | create_opp_for_contact | "Create opportunity for %{name}" | 商談セクションに表示 |
| エラー | missing_account_name | "Account name is required." | 取引先名未入力時 |
| エラー | missing_opportunity_name | "Opportunity name is required." | 商談名バリデーション |
| エラー | share_contact | "Please select users and/or groups to share with." | Shared選択時に共有先未選択 |

## 例外処理

| 例外ケース | 処理内容 | 表示 |
|-----------|---------|------|
| バリデーションエラー | フォーム再表示 | エラーメッセージをフォーム上部に表示 |
| 認証エラー | ログイン画面にリダイレクト | Deviseのデフォルトメッセージ |
| 権限エラー | 403エラー | アクセス権限がありません |

## 備考

- form_for を使用したフォーム生成（promote_lead_path に送信）
- remote: true により Ajax 送信
- one_submit_only によりダブルサブミット防止
- Lead権限オプションを選択するとリードの権限設定を引き継ぐ
- 商談は名前を入力した場合のみ作成される（任意）
- 連絡先には氏名・連絡先・住所・SNS情報がリードから自動的に引き継がれる
- カスタムフィールドも連絡先に引き継がれる（同名フィールドが存在する場合）
- 変換後もリードレコードは削除されず、ステータスが「converted」に更新される
- 変換後の連絡先からは元リードへの参照（lead_id）が保持される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lead.rb | `app/models/entities/lead.rb` | promote メソッド（124-133行目）と convert メソッド（136-138行目）を確認 |
| 1-2 | contact.rb | `app/models/entities/contact.rb` | Contact.create_for メソッド（171-191行目）でリードからの引き継ぎを確認 |
| 1-3 | opportunity.rb | `app/models/entities/opportunity.rb` | Opportunity.create_for メソッド（153-167行目） |
| 1-4 | account.rb | `app/models/entities/account.rb` | Account.create_or_select_for メソッド（119-124行目） |

**読解のコツ**: promote メソッドが Account、Opportunity、Contact の3つを作成/選択し、すべて成功した場合にのみ convert が呼ばれる点を理解。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | leads_controller.rb | `app/controllers/entities/leads_controller.rb` | convertアクション（106-116行目） |
| 2-2 | leads_controller.rb | `app/controllers/entities/leads_controller.rb` | promoteアクション（120-134行目） |

**主要処理フロー**:
1. **109行目（convert）**: @account に Lead 権限で初期化、会社名をリードから取得
2. **111行目（convert）**: @opportunity に prospecting ステージ、キャンペーン・ソースをリードから設定
3. **121行目（promote）**: @lead.promote で3エンティティを一括作成
4. **126-127行目（promote）**: すべてのエラーが空の場合のみ @lead.convert を実行

#### Step 3: ビューを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _convert.html.haml | `app/views/leads/_convert.html.haml` | 変換フォームの構成 |
| 3-2 | _opportunity.html.haml | `app/views/leads/_opportunity.html.haml` | 商談入力セクション |
| 3-3 | _convert_permissions.html.haml | `app/views/leads/_convert_permissions.html.haml` | 権限設定セクション |

**主要処理フロー**:
- **2行目（_convert）**: promote_lead_path に remote: true で送信
- **4-6行目**: account の user_id と access を隠しフィールドで送信
- **15行目**: account_select_or_create ヘルパーで取引先選択/新規作成UI
- **20行目**: _opportunity パーシャルで商談入力
- **21行目**: _convert_permissions で権限設定

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

```
[HTTP Request: GET /leads/:id/convert]
    │
    ├─ routes.rb (115行目)
    │      └─ LeadsController#convert
    │
    ├─ LeadsController#convert (106-116行目)
    │      ├─ @account = Account.new(user: current_user, name: @lead.company, access: "Lead")
    │      ├─ @accounts = Account.my(current_user)
    │      ├─ @opportunity = Opportunity.new(stage: "prospecting", campaign: @lead.campaign)
    │      └─ respond_with(@lead)
    │
    └─ leads/_convert.html.haml
           ├─ form_for(@lead, url: promote_lead_path, remote: true)
           ├─ fields_for(@account)
           │      └─ account_select_or_create
           ├─ leads/_opportunity.html.haml
           │      └─ 商談情報入力フィールド
           └─ leads/_convert_permissions.html.haml
                  └─ 権限選択ラジオボタン

[HTTP Request: PUT /leads/:id/promote]
    │
    └─ LeadsController#promote (120-134行目)
           ├─ @lead.promote(params)
           │      ├─ Account.create_or_select_for
           │      ├─ Opportunity.create_for
           │      └─ Contact.create_for
           │
           ├─ if errors.empty?
           │      └─ @lead.convert (status = 'converted')
           │
           └─ update_sidebar
```

### データフロー図

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

フォーム入力 ───────▶ params (account, opportunity, access)
                           │
                           ▼
                    LeadsController#promote
                           │
                           ▼
                    @lead.promote(params)
                           │
              ┌────────────┼────────────┐
              ▼            ▼            ▼
         Account      Opportunity    Contact
      create_or_select  create_for   create_for
              │            │            │
              ▼            ▼            ▼
          accounts     opportunities  contacts
           (DB)          (DB)         (DB)
              │            │            │
              └────────────┼────────────┘
                           │
                    すべて成功?
                      │    │
                    Yes    No
                      │    │
                      ▼    ▼
              @lead.convert  エラー返却
              (status='converted')
                      │
                      ▼
              Ajax レスポンス ───▶ 連絡先詳細/リード更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lead.rb | `app/models/entities/lead.rb` | モデル | promote, convert メソッド |
| contact.rb | `app/models/entities/contact.rb` | モデル | Contact.create_for |
| opportunity.rb | `app/models/entities/opportunity.rb` | モデル | Opportunity.create_for |
| account.rb | `app/models/entities/account.rb` | モデル | Account.create_or_select_for |
| leads_controller.rb | `app/controllers/entities/leads_controller.rb` | コントローラー | convert, promoteアクション |
| _convert.html.haml | `app/views/leads/_convert.html.haml` | ビュー | 変換フォームメインテンプレート |
| _opportunity.html.haml | `app/views/leads/_opportunity.html.haml` | ビュー | 商談入力セクション |
| _convert_permissions.html.haml | `app/views/leads/_convert_permissions.html.haml` | ビュー | 権限設定セクション |
| routes.rb | `config/routes.rb` | 設定 | URLルーティング定義 |
