# 機能設計書 27-リードの却下

## 概要

本ドキュメントは、Fat Free CRMシステムにおけるリードの却下機能の設計を定義する。この機能は、リードのステータスを「rejected（却下済み）」に変更し、営業パイプラインから除外する。

### 本機能の処理概要

リードの却下機能は、見込み顧客（リード）が営業対象として不適切であると判断された場合に、そのステータスを「rejected」に変更する機能である。

**業務上の目的・背景**：すべてのリードが商談に発展するわけではない。連絡不能、予算不足、ニーズ不一致、競合への発注決定など、様々な理由でリードを却下する必要がある。却下されたリードは一覧画面でフィルタリング可能であり、営業パイプラインの分析から除外される。これにより、有効なリードに集中した営業活動が可能になる。

**機能の利用シーン**：リードに複数回連絡しても応答がない場合、リードの予算が条件を満たさない場合、リードが競合製品を選択した場合、リードのニーズが自社製品と合致しない場合に利用される。

**主要な処理内容**：
1. 却下対象リードの特定
2. 却下権限の確認
3. リードステータスの更新（"rejected"）
4. サイドバー情報の更新

**関連システム・外部連携**：特になし（ステータス更新のみ）

**権限による制御**：CanCanによる認可制御が行われ、リードへの更新権限を持つユーザーのみが却下を実行可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 19 | リード変換画面 | 補助機能 | リードを却下済みステータスに変更 |

## 機能種別

CRUD操作（UPDATE） / ステータス更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | リードID | 数値、存在確認 |

### 入力データソース

- URL: PUT `/leads/:id/reject`
- HTTPメソッド: PUT
- データソース: URLパラメータのみ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @lead | Lead | 却下されたリードオブジェクト |

### 出力先

- HTML形式: リダイレクト（リード一覧画面）
- JS形式: AJAX応答（reject.js.haml）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ PUT /leads/:id/reject を受信
2. 認証・認可チェック
   └─ CanCanによる権限確認
3. リード取得
   └─ 指定IDのリードを取得
4. ステータス更新
   └─ @lead.reject（status="rejected"）
5. サイドバー更新
   └─ update_sidebar呼び出し
6. レスポンス生成
   └─ フォーマットに応じた出力
```

### フローチャート

```mermaid
flowchart TD
    A[PUT /leads/:id/reject] --> B[認証チェック]
    B --> C{認可チェック}
    C -->|許可| D[リードデータ取得]
    C -->|拒否| E[403 Forbidden]
    D --> F[@lead.reject]
    F --> G[update_sidebar]
    G --> H{フォーマット判定}
    H -->|HTML| I[フラッシュメッセージ設定]
    I --> J[リダイレクト]
    H -->|JS| K[AJAX応答]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-27-01 | ステータス更新 | statusを"rejected"に更新 | 常時 |
| BR-27-02 | バリデーションなし | rejectメソッドはupdate_attributeを使用し、バリデーションをスキップ | 常時 |
| BR-27-03 | フラッシュメッセージ | HTML応答時は「{リード名}を却下しました」メッセージを表示 | HTML応答時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リード更新 | leads | UPDATE | statusを"rejected"に更新 |

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

#### leads

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | status | 'rejected' | rejectメソッドで更新 |
| UPDATE | updated_at | 現在日時 | 自動設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | Not Found | 指定IDのリードが存在しない | エラーページ表示 |
| 403 | Forbidden | 更新権限がない | エラーページ表示 |

### リトライ仕様

リトライは実装されていない（冪等操作）

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

- ステータス更新のみの単純なトランザクション
- update_attributeはバリデーションをスキップ

## パフォーマンス要件

- 却下処理のレスポンスタイム: 1秒以内

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

- CanCanによる認可制御でアクセス権限をチェック
- 確認ダイアログで誤操作を防止

## 備考

- 却下済みリードは一覧画面でフィルタリング表示可能
- 却下操作は取り消し可能（editアクションでstatusを変更）
- 確認ダイアログはLeadsHelperのconfirm_rejectメソッドで生成

---

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

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

### 推奨読解順序

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

リードのステータス更新ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lead.rb | `app/models/entities/lead.rb` | rejectメソッド |

**読解のコツ**:
- **141-143行目**: rejectメソッド - update_attributeでstatusを"rejected"に更新
- update_attributeはバリデーションをスキップする点に注意

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

コントローラーのrejectアクションがエントリーポイントである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | leads_controller.rb | `app/controllers/entities/leads_controller.rb` | rejectアクションの実装 |

**主要処理フロー**:
1. **138-148行目** (rejectアクション):
   - **139行目**: @lead.reject呼び出し
   - **140行目**: update_sidebar呼び出し
   - **143-145行目**: HTML応答時のフラッシュメッセージとリダイレクト

#### Step 3: ヘルパーを理解する

確認ダイアログの生成を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | leads_helper.rb | `app/helpers/leads_helper.rb` | confirm_reject、link_to_rejectメソッド |

**主要処理フロー**:
- **27-29行目**: link_to_reject - 却下リンクの生成
- **32-39行目**: confirm_reject - 確認ダイアログの生成（JavaScript）

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

却下後の画面更新を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | reject.js.haml | `app/views/leads/reject.js.haml` | AJAX応答でのDOM更新 |

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

```
LeadsController#reject
    │
    ├─ @lead.reject
    │      └─ update_attribute(:status, "rejected")
    │
    ├─ update_sidebar
    │      ├─ get_data_for_sidebar (一覧画面から)
    │      └─ get_data_for_sidebar(:campaign) (キャンペーン画面から)
    │
    └─ respond_with(@lead)
           ├─ format.html
           │      ├─ flash[:notice] = t(:msg_asset_rejected, ...)
           │      └─ redirect_to leads_path
           │
           └─ format.js
                  └─ reject.js.haml
```

### データフロー図

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

PUT /leads/:id/reject ───▶ LeadsController#reject ───▶ HTML/JS
      │                           │
      │                           ├─▶ Lead#reject
      │                           │       └─▶ [leads]テーブル UPDATE
      │                           │
      │                           └─▶ update_sidebar
      │
      └─▶ reject.js.haml / リダイレクト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| leads_controller.rb | `app/controllers/entities/leads_controller.rb` | コントローラー | リード操作のエントリーポイント |
| lead.rb | `app/models/entities/lead.rb` | モデル | rejectメソッドの実装 |
| leads_helper.rb | `app/helpers/leads_helper.rb` | ヘルパー | 確認ダイアログ生成 |
| reject.js.haml | `app/views/leads/reject.js.haml` | ビュー | AJAX応答でのDOM更新 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
