Sample Process.Plugin Implementation for Lead Conversion

In this example, an Apex class implements the Process.Plugin interface and converts a lead into an account, contact, and optionally, an opportunity. Test methods for the plug-in are also included. This implementation can be called from a flow via a legacy Apex action.

We recommend using the @InvocableMethod annotation instead of the Process.Plugin interface.

  • The interface doesn’t support Blob, Collection, and sObject, data types, and it doesn’t support bulk operations. After you implement the interface on a class, the class can be referenced only from flows.
  • The annotation supports all data types and bulk operations. After you implement the annotation on a class, the class can be referenced from flows, processes, and the Custom Invocable Actions REST API endpoint.
  • Legacy Apex actions aren’t supported in auto-layout in Flow Builder. Legacy Apex actions are only available to be added in free-form in Flow Builder. Existing actions can be edited in both auto-layout and free-form mode.
  • You can customize how invocable actions created with @InvocableMethod appear in Flow Builder by using the InvocableActionExtension metadata file. Control parameter order, add picklists, create custom headers, and build partial custom property editors.

Tip

1// Converts a lead as an action in a flow.
2global with sharing class VWFConvertLead implements Process.Plugin {
3    // This method runs when called by a flow's legacy Apex action.
4    global Process.PluginResult invoke(
5        Process.PluginRequest request) {
6
7        // Set up variables to store input parameters from
8        // the flow.
9        String leadID = (String) request.inputParameters.get(
10            'LeadID');
11        String contactID = (String)
12            request.inputParameters.get('ContactID');
13        String accountID = (String)
14            request.inputParameters.get('AccountID');
15        String convertedStatus = (String)
16            request.inputParameters.get('ConvertedStatus');
17        Boolean overWriteLeadSource = (Boolean)
18            request.inputParameters.get('OverwriteLeadSource');
19        Boolean createOpportunity = (Boolean)
20            request.inputParameters.get('CreateOpportunity');
21        String opportunityName = (String)
22            request.inputParameters.get('ContactID');
23        Boolean sendEmailToOwner = (Boolean)
24            request.inputParameters.get('SendEmailToOwner');
25
26        // Set the default handling for booleans.
27        if (overWriteLeadSource == null)
28            overWriteLeadSource = false;
29        if (createOpportunity == null)
30            createOpportunity = true;
31        if (sendEmailToOwner == null)
32            sendEmailToOwner = false;
33
34        // Convert the lead by passing it to a helper method.
35        Map<String,Object> result = new Map<String,Object>();
36        result = convertLead(leadID, contactID, accountID,
37            convertedStatus, overWriteLeadSource,
38            createOpportunity, opportunityName,
39            sendEmailToOwner);
40
41        return new Process.PluginResult(result);
42    }
43
44    // This method describes the plug-in and its inputs from
45    // and outputs to the flow.
46    // Implementing this method makes the class available
47    // in Flow Builder as a legacy Apex action.
48    global Process.PluginDescribeResult describe() {
49        // Set up plugin metadata
50        Process.PluginDescribeResult result = new
51            Process.PluginDescribeResult();
52        result.description =
53            'The LeadConvert Flow Plug-in converts a lead into ' +
54            'an account, a contact, and ' +
55            '(optionally)an opportunity.';
56        result.tag = 'Lead Management';
57
58        // Create a list that stores both mandatory and optional
59        // input parameters from the flow.
60        // NOTE: Only primitive types (STRING, NUMBER, etc.) are
61        // supported. Collections aren't supported.
62        result.inputParameters = new
63            List<Process.PluginDescribeResult.InputParameter>{
64            // Lead ID (mandatory)
65            new Process.PluginDescribeResult.InputParameter(
66                'LeadID',
67                Process.PluginDescribeResult.ParameterType.STRING,
68                true),
69            // Account Id (optional)
70            new Process.PluginDescribeResult.InputParameter(
71                'AccountID',
72                Process.PluginDescribeResult.ParameterType.STRING,
73                false),
74            // Contact ID (optional)
75            new Process.PluginDescribeResult.InputParameter(
76                'ContactID',
77                Process.PluginDescribeResult.ParameterType.STRING,
78                false),
79            // Status to use once converted
80            new Process.PluginDescribeResult.InputParameter(
81                'ConvertedStatus',
82                Process.PluginDescribeResult.ParameterType.STRING,
83                true),
84            new Process.PluginDescribeResult.InputParameter(
85                'OpportunityName',
86                Process.PluginDescribeResult.ParameterType.STRING,
87                false),
88            new Process.PluginDescribeResult.InputParameter(
89                'OverwriteLeadSource',
90                Process.PluginDescribeResult.ParameterType.BOOLEAN,
91                false),
92            new Process.PluginDescribeResult.InputParameter(
93                'CreateOpportunity',
94                Process.PluginDescribeResult.ParameterType.BOOLEAN,
95                false),
96            new Process.PluginDescribeResult.InputParameter(
97                'SendEmailToOwner',
98                Process.PluginDescribeResult.ParameterType.BOOLEAN,
99                false)
100        };
101
102        // Create a list that stores output parameters sent
103        // to the flow.
104        result.outputParameters = new List<
105            Process.PluginDescribeResult.OutputParameter>{
106            // Account ID of the converted lead
107            new Process.PluginDescribeResult.OutputParameter(
108                'AccountID',
109                Process.PluginDescribeResult.ParameterType.STRING),
110            // Contact ID of the converted lead
111            new Process.PluginDescribeResult.OutputParameter(
112                'ContactID',
113                Process.PluginDescribeResult.ParameterType.STRING),
114            // Opportunity ID of the converted lead
115            new Process.PluginDescribeResult.OutputParameter(
116                'OpportunityID',
117                Process.PluginDescribeResult.ParameterType.STRING)
118        };
119
120        return result;
121    }
122
123    /**
124     * Implementation of the LeadConvert plug-in.
125     * Converts a given lead with several options:
126     * leadID - ID of the lead to convert
127     * contactID -
128     * accountID - ID of the Account to attach the converted
129     *  Lead/Contact/Opportunity to.
130     * convertedStatus -
131     * overWriteLeadSource -
132     * createOpportunity - true if you want to create a new
133     *  Opportunity upon conversion
134     * opportunityName - Name of the new Opportunity.
135     * sendEmailtoOwner - true if you are changing owners upon
136     *  conversion and want to notify the new Opportunity owner.
137     *
138     * returns: a Map with the following output:
139     * AccountID - ID of the Account created or attached
140     *  to upon conversion.
141     * ContactID - ID of the Contact created or attached
142     *  to upon conversion.
143     * OpportunityID - ID of the Opportunity created
144     *  upon conversion.
145     */
146    public Map<String,String> convertLead (
147                               String leadID,
148                               String contactID,
149                               String accountID,
150                               String convertedStatus,
151                               Boolean overWriteLeadSource,
152                               Boolean createOpportunity,
153                               String opportunityName,
154                               Boolean sendEmailToOwner
155        ) {
156        Map<String,String> result = new Map<String,String>();
157
158        if (leadId == null) throw new ConvertLeadPluginException(
159            'Lead Id cannot be null');
160
161        // check for multiple leads with the same ID
162        Lead[] leads = [Select Id, FirstName, LastName, Company
163            From Lead where Id = :leadID WITH USER_MODE];
164        if (leads.size() > 0) {
165            Lead l = leads[0];
166            // CheckAccount = true, checkContact = false
167            if (accountID == null && l.Company != null) {
168                Account[] accounts = [Select Id, Name FROM Account
169                    where Name = :l.Company WITH USER_MODE LIMIT 1];
170                if (accounts.size() > 0) {
171                    accountId = accounts[0].id;
172                }
173            }
174
175            // Perform the lead conversion.
176            Database.LeadConvert lc = new Database.LeadConvert();
177            lc.setLeadId(leadID);
178            lc.setOverwriteLeadSource(overWriteLeadSource);
179            lc.setDoNotCreateOpportunity(!createOpportunity);
180            lc.setConvertedStatus(convertedStatus);
181            if (sendEmailToOwner != null) lc.setSendNotificationEmail(
182                sendEmailToOwner);
183            if (accountId != null && accountId.length() > 0)
184                lc.setAccountId(accountId);
185            if (contactId != null && contactId.length() > 0)
186                lc.setContactId(contactId);
187            if (createOpportunity) {
188                lc.setOpportunityName(opportunityName);
189            }
190
191            Database.LeadConvertResult lcr = Database.convertLead(
192                lc, true, AccessLevel.USER_MODE);
193            if (lcr.isSuccess()) {
194                result.put('AccountID', lcr.getAccountId());
195                result.put('ContactID', lcr.getContactId());
196                if (createOpportunity) {
197                    result.put('OpportunityID',
198                        lcr.getOpportunityId());
199                }
200            } else {
201                String error = lcr.getErrors()[0].getMessage();
202                throw new ConvertLeadPluginException(error);
203            }
204        } else {
205            throw new ConvertLeadPluginException(
206                'No leads found with Id : "' + leadId + '"');
207        }
208        return result;
209    }
210
211    // Utility exception class
212    public with sharing class ConvertLeadPluginException extends Exception {}
213}
1// Test class for the lead convert Apex plug-in.
2@IsTest
3private with sharing class VWFConvertLeadTest {
4    @IsTest
5    static void basicTest() {
6        // Create test lead
7        Lead testLead = new Lead(
8           Company='Test Lead',FirstName='John',LastName='Doe');
9        insert as user testLead;
10
11        LeadStatus convertStatus =
12           [Select Id, MasterLabel from LeadStatus
13           WHERE IsConverted=true WITH USER_MODE LIMIT 1];
14
15        // Create test conversion
16        VWFConvertLead aLeadPlugin = new VWFConvertLead();
17        Map<String,Object> inputParams = new Map<String,Object>();
18        Map<String,Object> outputParams = new Map<String,Object>();
19
20        inputParams.put('LeadID',testLead.ID);
21        inputParams.put('ConvertedStatus',
22           convertStatus.MasterLabel);
23
24        Process.PluginRequest request = new
25           Process.PluginRequest(inputParams);
26        Process.PluginResult result;
27        result = aLeadPlugin.invoke(request);
28
29        Lead aLead = [select name, id, isConverted
30                       from Lead where id = :testLead.ID WITH USER_MODE];
31        Assert.isTrue(aLead.isConverted);
32
33    }
34
35     /*
36      * This tests lead conversion with
37      * the Account ID specified.
38      */
39    @IsTest
40    static void basicTestwithAccount() {
41
42        // Create test lead
43        Lead testLead = new Lead(
44            Company='Test Lead',FirstName='John',LastName='Doe');
45        insert as user testLead;
46
47        Account testAccount = new Account(name='Test Account');
48        insert as user testAccount;
49
50           // System.debug('ACCOUNT BEFORE' + testAccount.ID);
51
52        LeadStatus convertStatus = [SELECT Id, MasterLabel
53                    FROM LeadStatus WHERE IsConverted=true WITH USER_MODE LIMIT 1];
54
55        // Create test conversion
56        VWFConvertLead aLeadPlugin = new VWFConvertLead();
57        Map<String,Object> inputParams = new Map<String,Object>();
58        Map<String,Object> outputParams = new Map<String,Object>();
59
60        inputParams.put('LeadID',testLead.ID);
61        inputParams.put('AccountID',testAccount.ID);
62        inputParams.put('ConvertedStatus',
63            convertStatus.MasterLabel);
64
65        Process.PluginRequest request = new
66            Process.PluginRequest(inputParams);
67        Process.PluginResult result;
68        result = aLeadPlugin.invoke(request);
69
70        Lead aLead =
71            [SELECT name, id, isConverted, convertedAccountID
72             FROM Lead WHERE id = :testLead.ID WITH USER_MODE];
73        Assert.isTrue(aLead.isConverted);
74        //System.debug('ACCOUNT AFTER' + aLead.convertedAccountID);
75        Assert.areEqual(testAccount.ID, aLead.convertedAccountID);
76    }
77
78    /*
79     * This tests lead conversion with the Account ID specified.
80    */
81    @IsTest
82    static void basicTestwithAccounts() {
83
84        // Create test lead
85        Lead testLead = new Lead(
86            Company='Test Lead',FirstName='John',LastName='Doe');
87        insert as user testLead;
88
89        Account testAccount1 = new Account(name='Test Lead');
90        insert as user testAccount1;
91        Account testAccount2 = new Account(name='Test Lead');
92        insert as user testAccount2;
93
94           // System.debug('ACCOUNT BEFORE' + testAccount.ID);
95
96        LeadStatus convertStatus = [SELECT Id, MasterLabel
97            FROM LeadStatus WHERE IsConverted=true WITH USER_MODE LIMIT 1];
98
99        // Create test conversion
100        VWFConvertLead aLeadPlugin = new VWFConvertLead();
101        Map<String,Object> inputParams = new Map<String,Object>();
102        Map<String,Object> outputParams = new Map<String,Object>();
103
104        inputParams.put('LeadID',testLead.ID);
105        inputParams.put('ConvertedStatus',
106            convertStatus.MasterLabel);
107
108        Process.PluginRequest request = new
109            Process.PluginRequest(inputParams);
110        Process.PluginResult result;
111        result = aLeadPlugin.invoke(request);
112
113        Lead aLead =
114            [SELECT name, id, isConverted, convertedAccountID
115            FROM Lead WHERE id = :testLead.ID WITH USER_MODE];
116        Assert.isTrue(aLead.isConverted);
117    }
118
119
120     /*
121      * -ve Test
122      */
123    @IsTest
124    static void errorTest() {
125
126        // Create test lead
127        // Lead testLead = new Lead(Company='Test Lead',
128        //   FirstName='John',LastName='Doe');
129        LeadStatus convertStatus = [SELECT Id, MasterLabel
130            FROM LeadStatus WHERE IsConverted=true WITH USER_MODE LIMIT 1];
131
132        // Create test conversion
133        VWFConvertLead aLeadPlugin = new VWFConvertLead();
134        Map<String,Object> inputParams = new Map<String,Object>();
135        Map<String,Object> outputParams = new Map<String,Object>();
136        inputParams.put('LeadID','00Q7XXXXxxxxxxx');
137        inputParams.put('ConvertedStatus',convertStatus.MasterLabel);
138
139        Process.PluginRequest request = new
140            Process.PluginRequest(inputParams);
141        Process.PluginResult result;
142        try {
143            result = aLeadPlugin.invoke(request);
144        }
145        catch (Exception e) {
146          System.debug('EXCEPTION' + e);
147          Assert.areEqual(1,1);
148        }
149
150    }
151
152
153     /*
154      * This tests the describe() method
155      */
156    @IsTest
157    static void describeTest() {
158
159        VWFConvertLead aLeadPlugin =
160            new VWFConvertLead();
161        Process.PluginDescribeResult result =
162            aLeadPlugin.describe();
163
164        Assert.areEqual(
165            8, result.inputParameters.size());
166        Assert.areEqual(
167            3, result.OutputParameters.size());
168
169     }
170
171}

DID THIS ARTICLE SOLVE YOUR ISSUE?
Let us know so we can improve!