0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

プロコード(Apex)とフローの使い分け

0
Posted at

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を作成し、関連するAccountContactを自動で関連付け。
  2. 特定のフェーズに到達したらタスクを自動作成

    • Opportunity.StageNameが「提案済み」になった際に、自動的に「フォローアップ」のタスクを作成し、商談の担当者に割り当て。
  3. 取引先の業種に応じてカスタム項目を更新

    • Account.Industryの値に応じて、Account.Segment__c(カスタム項目)を自動設定(例:「金融業」なら「高優先度顧客」)。
  4. 商談が成立したら関連レコードのフィールド更新

    • Opportunity.StageNameが「成約」になった際に、関連するContactStatus__cを「顧客」に更新。
  5. 商談が一定期間更新されていなければアラート通知

    • Opportunity.LastModifiedDateが30日以上前のものをチェックし、商談担当者にSlackやメールで通知。

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


1. リードの自動評価(カスタムスコアリングロジック)

要件

  • Leadの特定の項目(例:IndustryAnnualRevenueLeadSourceなど)に基づいて、独自のスコアリングロジックを適用。
  • スコアが一定以上ならStatusQualifiedに変更。

実装

① 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';
            }
        }
    }
}

② トリガー

trigger LeadTrigger on Lead (before insert, before update) {
    if (Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)) {
        LeadScoringService.assignLeadScore(Trigger.new);
    }
}

2. 商談の金額分割ロジック(カスタム売上配分)

要件

  • OpportunityAmountを、特定の担当者ごとにOpportunitySplitへ分割する。
  • OpportunityTeamMemberに応じた割合で分配。

実装

① 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;
        }
    }
}

② トリガー

trigger OpportunityTrigger on Opportunity (after insert, after update) {
    if (Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {
        OpportunitySplitService.createOpportunitySplits(Trigger.new);
    }
}

3. メール送信のカスタマイズ(Salesforceから動的コンテンツメール送信)

要件

  • OpportunityStageNameが「契約書送付」に変更されたら、取引先の担当者にメールを送信。

実装

① 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);
        }
    }
}

② トリガー

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. リードの自動所有者割り当て(複雑な条件ロジック)

要件

  • LeadIndustryCountryAnnualRevenueに応じて最適な営業担当者を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'; // その他
            }
        }
    }
}

② トリガー

trigger LeadTrigger on Lead (before insert, before update) {
    LeadAssignmentService.assignOwner(Trigger.new);
}

5. 見積書のPDF自動生成と保存

要件

  • Quoteが作成された際に、自動的にPDFを生成しQuoteの関連ファイルとして保存。

実装

① 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;
        }
    }
}

② トリガー

trigger QuoteTrigger on Quote (after insert) {
    QuotePDFService.generateAndAttachPDF(Trigger.new);
}

まとめ

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

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

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?