Apexを使ったロジックが必要な具体的なケースを5つ、フローで対応できるケースを5つ紹介します。
フローで対応できるものは、極力Apexを使わずに済む場面を挙げます。
Apexクラスが必要な事例(フローでは対応困難なもの)
-
リードの自動評価(カスタムスコアリングロジック)
- Account Engagementのリードスコアとは別に、独自のスコアリングロジックをApexで実装し、特定の基準を満たしたリードのみをSales Cloudに同期。
-
Leadオブジェクトのbefore insert/updateトリガーで処理。
-
商談の金額分割ロジック(カスタム売上配分)
-
Opportunityオブジェクトに登録された金額を、関連するOpportunitySplitレコードに特定のルール(たとえば担当営業ごとの売上割合)に基づいて自動分割。 -
after insert/updateトリガーで、OpportunitySplitを適切に作成・更新。
-
-
メール送信のカスタマイズ(Salesforceから動的コンテンツメール送信)
-
Opportunityのフェーズが「契約書送付」に変更された際に、取引先の最新のメールアドレスを取得し、Apexでメール送信。 -
Messaging.SingleEmailMessageを活用して動的なメールを生成。
-
-
リードの自動所有者割り当て(複雑な条件ロジック)
-
Leadの地域・業種・過去のやりとり履歴などを考慮し、営業担当者をApexで動的に割り当て。 -
before insert/updateトリガーで所有者を変更。
-
-
見積書のPDF自動生成と保存
-
Quoteオブジェクトのレコードが作成された際に、Apexを使ってVisualforce + PDF形式の見積書を自動生成し、Quoteの関連ファイルとして添付。 -
after insertトリガー +ContentVersionの作成を実行。
-
フローで対応可能な事例(Apex不要)
-
リードのスコアが一定値を超えたら商談を自動作成
-
Lead.Scoreが特定値を超えた場合に、Opportunityを作成し、関連するAccountとContactを自動で関連付け。
-
-
特定のフェーズに到達したらタスクを自動作成
-
Opportunity.StageNameが「提案済み」になった際に、自動的に「フォローアップ」のタスクを作成し、商談の担当者に割り当て。
-
-
取引先の業種に応じてカスタム項目を更新
-
Account.Industryの値に応じて、Account.Segment__c(カスタム項目)を自動設定(例:「金融業」なら「高優先度顧客」)。
-
-
商談が成立したら関連レコードのフィールド更新
-
Opportunity.StageNameが「成約」になった際に、関連するContactのStatus__cを「顧客」に更新。
-
-
商談が一定期間更新されていなければアラート通知
-
Opportunity.LastModifiedDateが30日以上前のものをチェックし、商談担当者にSlackやメールで通知。
-
以下に、Apexクラスが必要な事例について、それぞれの実装例を記載します。
各ケースでApexトリガーとクラスを分けて実装し、テストクラスも考慮した構成にします。
1. リードの自動評価(カスタムスコアリングロジック)
要件
-
Leadの特定の項目(例:Industry、AnnualRevenue、LeadSourceなど)に基づいて、独自のスコアリングロジックを適用。 - スコアが一定以上なら
StatusをQualifiedに変更。
実装
① 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. 商談の金額分割ロジック(カスタム売上配分)
要件
-
OpportunityのAmountを、特定の担当者ごとに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から動的コンテンツメール送信)
要件
-
OpportunityのStageNameが「契約書送付」に変更されたら、取引先の担当者にメールを送信。
実装
① 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. リードの自動所有者割り当て(複雑な条件ロジック)
要件
-
LeadのIndustry、Country、AnnualRevenueに応じて最適な営業担当者を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を利用することで、よりパフォーマンスを向上させることも可能です。