プロコード（Apex）とフローの使い分け

Apexを使ったロジックが必要な具体的なケースを5つ、フローで対応できるケースを5つ紹介します。  
フローで対応できるものは、極力Apexを使わずに済む場面を挙げます。  

---

## **Apexクラスが必要な事例（フローでは対応困難なもの）**
1. **リードの自動評価（カスタムスコアリングロジック）**
   - Account Engagementのリードスコアとは別に、独自のスコアリングロジックをApexで実装し、特定の基準を満たしたリードのみをSales Cloudに同期。
   - `Lead`オブジェクトの`before insert/update`トリガーで処理。

2. **商談の金額分割ロジック（カスタム売上配分）**
   - `Opportunity`オブジェクトに登録された金額を、関連する`OpportunitySplit`レコードに特定のルール（たとえば担当営業ごとの売上割合）に基づいて自動分割。
   - `after insert/update`トリガーで、`OpportunitySplit`を適切に作成・更新。

3. **メール送信のカスタマイズ（Salesforceから動的コンテンツメール送信）**
   - `Opportunity`のフェーズが「契約書送付」に変更された際に、取引先の最新のメールアドレスを取得し、Apexでメール送信。
   - `Messaging.SingleEmailMessage`を活用して動的なメールを生成。

4. **リードの自動所有者割り当て（複雑な条件ロジック）**
   - `Lead`の地域・業種・過去のやりとり履歴などを考慮し、営業担当者をApexで動的に割り当て。
   - `before insert/update`トリガーで所有者を変更。

5. **見積書のPDF自動生成と保存**
   - `Quote`オブジェクトのレコードが作成された際に、Apexを使ってVisualforce + PDF形式の見積書を自動生成し、`Quote`の関連ファイルとして添付。
   - `after insert`トリガー + `ContentVersion`の作成を実行。

---

## **フローで対応可能な事例（Apex不要）**
1. **リードのスコアが一定値を超えたら商談を自動作成**
   - `Lead.Score`が特定値を超えた場合に、`Opportunity`を作成し、関連する`Account`と`Contact`を自動で関連付け。

2. **特定のフェーズに到達したらタスクを自動作成**
   - `Opportunity.StageName`が「提案済み」になった際に、自動的に「フォローアップ」のタスクを作成し、商談の担当者に割り当て。

3. **取引先の業種に応じてカスタム項目を更新**
   - `Account.Industry`の値に応じて、`Account.Segment__c`（カスタム項目）を自動設定（例：「金融業」なら「高優先度顧客」）。

4. **商談が成立したら関連レコードのフィールド更新**
   - `Opportunity.StageName`が「成約」になった際に、関連する`Contact`の`Status__c`を「顧客」に更新。

5. **商談が一定期間更新されていなければアラート通知**
   - `Opportunity.LastModifiedDate`が30日以上前のものをチェックし、商談担当者にSlackやメールで通知。

---

以下に、Apexクラスが必要な事例について、それぞれの実装例を記載します。  
各ケースでApexトリガーとクラスを分けて実装し、テストクラスも考慮した構成にします。  

---

# **1. リードの自動評価（カスタムスコアリングロジック）**
### **要件**
- `Lead`の特定の項目（例：`Industry`、`AnnualRevenue`、`LeadSource`など）に基づいて、独自のスコアリングロジックを適用。
- スコアが一定以上なら`Status`を`Qualified`に変更。

### **実装**
#### **① Apexクラス**
```apex
public class LeadScoringService {
    public static void assignLeadScore(List<Lead> leads) {
        for (Lead lead : leads) {
            Integer score = 0;

            if (lead.Industry == 'Technology') {
                score += 30;
            }
            if (lead.AnnualRevenue > 1000000) {
                score += 20;
            }
            if (lead.LeadSource == 'Web') {
                score += 10;
            }

            lead.Score__c = score; // カスタム項目
            if (score >= 50) {
                lead.Status = 'Qualified';
            }
        }
    }
}
```

#### **② トリガー**
```apex
trigger LeadTrigger on Lead (before insert, before update) {
    if (Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)) {
        LeadScoringService.assignLeadScore(Trigger.new);
    }
}
```

---

# **2. 商談の金額分割ロジック（カスタム売上配分）**
### **要件**
- `Opportunity`の`Amount`を、特定の担当者ごとに`OpportunitySplit`へ分割する。
- `OpportunityTeamMember`に応じた割合で分配。

### **実装**
#### **① Apexクラス**
```apex
public class OpportunitySplitService {
    public static void createOpportunitySplits(List<Opportunity> opportunities) {
        List<OpportunitySplit> splitsToInsert = new List<OpportunitySplit>();

        for (Opportunity opp : opportunities) {
            List<OpportunityTeamMember> teamMembers = [SELECT UserId, SplitPercentage__c 
                                                       FROM OpportunityTeamMember 
                                                       WHERE OpportunityId = :opp.Id];
            for (OpportunityTeamMember member : teamMembers) {
                OpportunitySplit split = new OpportunitySplit();
                split.OpportunityId = opp.Id;
                split.SplitOwnerId = member.UserId;
                split.SplitTypeId = 'Revenue'; // 必要に応じてカスタム設定
                split.Amount = (opp.Amount * member.SplitPercentage__c) / 100;
                splitsToInsert.add(split);
            }
        }
        if (!splitsToInsert.isEmpty()) {
            insert splitsToInsert;
        }
    }
}
```

#### **② トリガー**
```apex
trigger OpportunityTrigger on Opportunity (after insert, after update) {
    if (Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {
        OpportunitySplitService.createOpportunitySplits(Trigger.new);
    }
}
```

---

# **3. メール送信のカスタマイズ（Salesforceから動的コンテンツメール送信）**
### **要件**
- `Opportunity`の`StageName`が「契約書送付」に変更されたら、取引先の担当者にメールを送信。

### **実装**
#### **① Apexクラス**
```apex
public class OpportunityEmailService {
    public static void sendContractEmail(List<Opportunity> opportunities) {
        List<Messaging.SingleEmailMessage> emails = new List<Messaging.SingleEmailMessage>();

        for (Opportunity opp : opportunities) {
            if (opp.StageName == '契約書送付') {
                Contact contact = [SELECT Email FROM Contact WHERE AccountId = :opp.AccountId LIMIT 1];
                
                if (contact != null && String.isNotBlank(contact.Email)) {
                    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
                    mail.setToAddresses(new List<String>{contact.Email});
                    mail.setSubject('契約書の送付について');
                    mail.setPlainTextBody('契約書を送付しましたのでご確認ください。');
                    emails.add(mail);
                }
            }
        }
        if (!emails.isEmpty()) {
            Messaging.sendEmail(emails);
        }
    }
}
```

#### **② トリガー**
```apex
trigger OpportunityTrigger on Opportunity (after update) {
    List<Opportunity> updatedOpportunities = new List<Opportunity>();
    for (Opportunity opp : Trigger.new) {
        if (opp.StageName == '契約書送付' && Trigger.oldMap.get(opp.Id).StageName != '契約書送付') {
            updatedOpportunities.add(opp);
        }
    }
    if (!updatedOpportunities.isEmpty()) {
        OpportunityEmailService.sendContractEmail(updatedOpportunities);
    }
}
```

---

# **4. リードの自動所有者割り当て（複雑な条件ロジック）**
### **要件**
- `Lead`の`Industry`、`Country`、`AnnualRevenue`に応じて最適な営業担当者をApexで割り当てる。

### **実装**
#### **① Apexクラス**
```apex
public class LeadAssignmentService {
    public static void assignOwner(List<Lead> leads) {
        for (Lead lead : leads) {
            if (lead.Industry == 'Technology' && lead.AnnualRevenue > 1000000) {
                lead.OwnerId = '005XXXXXXXXXXXX'; // 特定の営業担当
            } else if (lead.Country == 'Japan') {
                lead.OwnerId = '005YYYYYYYYYYYY'; // 日本担当者
            } else {
                lead.OwnerId = '005ZZZZZZZZZZZZ'; // その他
            }
        }
    }
}
```

#### **② トリガー**
```apex
trigger LeadTrigger on Lead (before insert, before update) {
    LeadAssignmentService.assignOwner(Trigger.new);
}
```

---

# **5. 見積書のPDF自動生成と保存**
### **要件**
- `Quote`が作成された際に、自動的にPDFを生成し`Quote`の関連ファイルとして保存。

### **実装**
#### **① Apexクラス**
```apex
public class QuotePDFService {
    public static void generateAndAttachPDF(List<Quote> quotes) {
        List<ContentVersion> contentList = new List<ContentVersion>();

        for (Quote quote : quotes) {
            PageReference pdfPage = Page.QuotePDF; // Visualforceページ（QuotePDF）を事前に作成
            pdfPage.getParameters().put('id', quote.Id);
            Blob pdfBlob = pdfPage.getContentAsPDF();

            ContentVersion content = new ContentVersion();
            content.Title = 'Quote_' + quote.Name + '.pdf';
            content.PathOnClient = '/Quote_' + quote.Name + '.pdf';
            content.VersionData = pdfBlob;
            contentList.add(content);
        }
        if (!contentList.isEmpty()) {
            insert contentList;
        }
    }
}
```

#### **② トリガー**
```apex
trigger QuoteTrigger on Quote (after insert) {
    QuotePDFService.generateAndAttachPDF(Trigger.new);
}
```

---

## **まとめ**
Apexが必要なケースは、**「高度なロジック」や「大量データ処理」** が絡む場面です。  
一方、フローは **「単純な条件分岐」「レコードの作成・更新」「通知」** には強いので、適材適所で使い分けるのがベストです。

これらのケースでは、フローだけでは対応が難しい**「複雑なロジックの実装」「データの動的処理」「外部リソースの活用」**が必要となるため、Apexが適しています。  

特に**バッチ処理**が必要な場合は`Batch Apex`を、**非同期処理**が必要な場合は`Queueable Apex`を利用することで、よりパフォーマンスを向上させることも可能です。