Last Updated on April 19, 2022 by Rakesh Gupta
Big Idea or Enduring Question:
How do you set automation to auto-convert marketing qualified leads?
When there is a chance of further negotiations with a lead, it can be converted into an account, contact, optionally an opportunity. In short, once the lead status has reached a certain stage, it can be qualified as a potential. On conversion, all the lead details are transferred in creating an account, contact, and optionally an opportunity. The lead conversion process is a manual process, if you want to automate it then you have to use Apex code. This article will help you to understand how to automate the lead conversion process using the Lightning Flow.
Objectives:
After reading this blog post, the reader will be able to:
- Use After-save Record-Triggered Flow to auto-convert marketing qualified leads
- Understand @InvocableMethod Annotation
- Use Schedule-Triggered Flow to call an Apex method
Business Use Case
Pamela Kline is working as a System administrator in Universal Container. She has received a requirement from the management to auto-convert marketing qualified (i.e. leads with Rating = Hot) leads and create an account and contact record.
Automation Champion Approach (I-do):
Let’s begin building this automation process.
Guided Practice (We-do):
There are 2 steps to solve Pamela’s business requirement using Lightning Flow. We must:
- Create an Apex class and test class
- Lightning Flow Steps:
- Define flow properties for record-triggered flow
- Adding an action to Call an Apex Class
Step 1: Create an Apex class and Test class
- Click Setup.
- In the Quick Find box, type Apex Classes.
- Clicks on the New button.
- Copy code from GitHub and paste it into your Apex Class.
- Click Save.
Repeat the above steps and click the Test class. You can get the code from my GitHub repo.
Step 2.1: Lightning Flow – Define Flow Properties
- Click Setup.
- In the Quick Find box, type Flows.
- Select Flows then click on the New Flows.
- Select the Record-Triggered Flow option and click on Next and configure the flow as follows:
- How do you want to start building: Freeform
- Trigger the Flow When: A record is created or Updated
- Run Flow: After the record is saved
- Object: Lead
- Select All Conditions Are Met (AND).
- Set Conditions
- Row 1
- Field: Lead | Rating
- Operator: Equals
- Value: Hot
- Row 1
- Choose the Option to Only when a record is updated to meet the condition requirements.
- Click Done.
Step 2.2: Lightning Flow – Call an Apex Class
The next step is to call the AutoConvertLeads class from flow so that when flow fires it auto-convert the leads.
- Under Toolbox, select Element.
- Drag-and-drop Action element onto the Flow designer.
- In the Action box, type AutoConvertLeads.
- Clicks on the AutoConvertLeads apex class.
- Enter a name in the Label field; the API Name will auto-populate.
- Set Input Values:
- Row 1:
- LeadIs: {!$Record.Id}
- Row 1:
- Click Done.
In the end, Steven’s Flow will look like the following screenshot:
Once everything looks good, perform the below steps:
- Click Save.
- Enter Flow Label the API Name will auto-populate.
- Click Show Advanced.
- Type: Record-Triggered Flow
- API Version for Running the Flow: 50
- Interview Label: Auto Convert Leads {!$Flow.CurrentDateTime}
- Click Save.
Almost there! Once everything looks good, click the Activate button.
Proof of Concept
Now onwards, if a business user updates the Lead Rating to Hot, Lightning Flow will automatically convert such leads and create an account as well as a contact.
- Currently, the lead Gaurav Pradhan is Open and the Rating is Warm as shown in the following screenshot:
- Now we update the Rating to Hot and see the flow magic.
- Flow auto converts the Lead and create an Account and Contact or it.
Note: – I will suggest you implement this first in your developer org, test it and then move it to production. The same approach will work for the case assignment rule. Download Apex and Test class from GitHub.
Process Builder Approach
Formative Assessment:
I want to hear from you!
What is one thing you learned from this post? How do you envision applying this new knowledge in the real world?
Let me know by Tweeting me at @automationchamp, or find me on LinkedIn.
Thanks, worked like a charm! exactly what i was looking for 🙂
I see in your last screenshot that in Classic it shows you the (standard) confirmation page of the conversion with the links to the newly created records.
Is it correct that that is not happening in Lightning? At least not in my case 🙂
Is there any way to enforce the confirmation page showing in LEX?
Thanks very much!
Hi Rakesh – this is incredibly helpful! One thing I’m running into with the below code is that the Lead will not convert if there’s no matching Account. My code is below; any suggestions? Thanks!
Public class AutoConvertLeads {
@InvocableMethod
public static void LeadAssign(List LeadIds) {
LeadStatus CLeadStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true Limit 1];
List MassLeadconvert = new List ();
List myLeads = [Select id, name, company from Lead where id IN: LeadIds];
List company = New List ();
for (Lead l: myLeads) {
company.add(l.company);
}
List matchAccount = [Select id, Name from account where Name IN: company];
for (Lead currentlead: myLeads) {
for (Account a: matchAccount) {
if (currentlead.company == a.Name) {
Database.LeadConvert Leadconvert = new Database.LeadConvert();
Leadconvert.setLeadId(currentlead.id);
Leadconvert.setAccountId(a.id);
Leadconvert.setConvertedStatus(CLeadStatus.MasterLabel);
Leadconvert.setDoNotCreateOpportunity(TRUE); //Remove this line if you want to create an opportunity from Lead Conversion
MassLeadconvert.add(Leadconvert);
Break;
} else {
Database.LeadConvert Leadconvert = new Database.LeadConvert();
Leadconvert.setLeadId(currentlead.id);
Leadconvert.setConvertedStatus(CLeadStatus.MasterLabel);
Leadconvert.setDoNotCreateOpportunity(TRUE); //Remove this line if you want to create an opportunity from Lead Conversion
MassLeadconvert.add(Leadconvert);
}
}
}
if (!MassLeadconvert.isEmpty()) {
List lcr = Database.convertLead(MassLeadconvert);
}
}
}
Hey Rakesh, This is a very useful article. One question I have, is it possible to define the Account record type that the lead converts to? Wondering should it be at the APEX class level, or perhaps just a delay action on the same process builder to update the record type? What would you suggest?
Thansk
Paul Carass
You can achieve it through two ways
Thanks Rakesh. I actually ended up doing it by Process Builder 😀
It’s working and very useful. Thank you for sharing.
Thanks for the feedback, Khing! I am glad this was useful!
Hey Rakesh,
First of all, thank you so much for sharing this!!!
I did have a quick question and I was hoping you could help… The issue I’m running into is when this process is triggered off by our engineering team (It works fine if I manually trigger the flow) but whenever they fire it off it gives an error like this…
Executed the default outcome
AUTOCONVERTLEADS (APEX): myRule_1_A1
Inputs:
LeadIds = {!myVariable_current.Id} (00Q9E000005HuWLUA0)
Error Occurred: An Apex error occurred: System.DmlException: ConvertLead failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Converted objects can only be owned by users. If the lead is not owned by a user, you must specify a user for the Owner field.: [OwnerId]
Do I need to include the OwnerId in the apex variables? 😱
Thanks in advance!
See this error message “EQUIRED_FIELD_MISSING, Converted objects can only be owned by users. If the lead is not owned by a user, you must specify a user for the Owner field.: [OwnerId]”
Please make sure that Lead is assigned to a user before conversion.
Hi Rakesh, thank you so much for this code. It works for me on my staging site but I am running into an issue with code coverage. It basically only says it has 25% code coverage and you need at least 75% to move it to production. Do you have any suggestions for how I can get it to 75%? Did you ever run into this issue?
Code coverage will depend on your Org customization and configuration. What part of the code are still in red?
Hi Rakesh,
That is the interesting part. No part of the actual code is in red but when I go to pull the Inbound change sets if I use the option to do the default or org tests it fails. If I kind of trick it and just use your test you provided in the git repo it works. That being said, when I try to update a lead I get this error “We can’t save this record because the “Convert Qualified Leads to Contacts” process failed. Give your Salesforce admin these details. An unhandled fault has occurred in this flow An unhandled fault has occurred while processing the flow. Please contact your system administrator for more information. Error ID: 2004881690-30735 (1505380676).” All I am doing is checking a picklist for 4 specific fields and then converting the lead to a contact. Thanks in advance for your help.
Check the Flow error email sent by Salesforce or use Debug Log to gather more information. Look at Debug Log very carefully and you will get the answer.
Hi Rakesh, I took a look at the logs and it appears that the issue has to do with duplicate leads being converted. It looks like the apex class test and process builder causes the class to get called twice. Have you run into this at all? I am trying to add something to check and make sure a contact doesn’t already exist but I am not sure how to do that. This is the error:
System.DmlException: ConvertLead failed. First exception on row 0; first error: CANNOT_UPDATE_CONVERTED_LEAD, This lead was already converted to the contact Joey Boy on 7/13/2018.: []
Looks like your process is firing twice. That is what i can see based on error message
Would having a test class cause it to fire twice? If I take this out of my test class ConvertLeadstoContacts.LeadAssign(Ids); completely then it only fires once and I don’t get that error in staging. That being said, I do get that error in production. Nothing with the test class gets fired in production, correct? Any idea how I could prevent this? I am trying to add some code that gets the lead by Id and checks the status. I am just not experience with apex code and can’t exactly figure out how to do that.
I think I almost have it. The only thing I am noticing is we have the DupCatcher app and it returns an error if the account name already exists. Any thoughts on how to avoid that? Sorry to keep asking questions about this.
In such cases, you need to modify Apex class to check for the duplicate account first before creating it.
Hi Rakesh,
Thanks again for all of your help. I saw another comment where you helped someone adjust the code to check for matching accounts. I was able to implement that and get it working. Thanks again for this great post and your quick replies to my questions. It is greatly appreciated.
Thanks, glad I could help!
Hello Rakesh,
Thank you for this post. It has been very helpful and is relevant for a similar problem I’m trying hard to solve. However, I’m still really struggling to get to exactly where I need and I hoping that if possible, you could kindly post a variation of the code that would allow for an additional variable(s) to be passed to the class from another field on the same lead. In particular, I’m intending to store an existing contact’s id (and that contact’s related account ID) on the Lead, so that when the process builder triggers the Apex Class it converts that lead to an existing contact as already specified on a field in that lead.
I suspect I need some code like below but also some code to get the variables from the Process Builder to the Apex Class for it to reference/use
– Leadconvert.setContactId(StoredContactId on currentlead)
– Leadconvert.setAccountId(StorcdAccountId on currentlead)
Thank you in advance,
Jonathan
Correct, you have to do something similar
Here are my suggestion if anyone wants to merge the lead with an existing account:
– Use Flow to identify the AccountId, if you want to merge
– Then use the new Apex class to Pass AccountId and LeadId
Public class AutoConvertLeads1 requestList) {
{ @InvocableMethod(label = ‘Auto Convert Leads’)
public static void LeadAssign(List
LeadStatus CLeadStatus= [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true Limit 1]; MassLeadconvert = new List(); lcr = Database.convertLead(MassLeadconvert);
List
for (Requests req: requestList){
Database.LeadConvert Leadconvert = new Database.LeadConvert();
Leadconvert.setLeadId(req.LeadId);
Leadconvert.setAccountId(req.AccountId);
Leadconvert.setConvertedStatus(CleadStatus.MasterLabel);
Leadconvert.setDoNotCreateOpportunity(TRUE); //Remove this line if you want to create an opportunity from Lead Conversion
MassLeadconvert.add(Leadconvert);
}
if (!MassLeadconvert.isEmpty())
{
List
}
}
public class Requests {
@InvocableVariable(label = ‘LeadId’ required = true)
public id LeadId;
@InvocableVariable(label = ‘AccountId’ required = false)
public Id AccountId;
}
}
Thanks for this post, code worked like a charm, was able to trigger rest of Lead Conversion Flow by IsConvert Process Builder criteria and then autolaunched flow to create related Account and Opportunity to complete a custom Lead conversion flow. 🙂 thank you.
Good to know! 🙂
Hi Rakesh, I tried your workaround but it gives me this error.
An Apex error occurred: System.DmlException: ConvertLead failed. First exception on row 0; first error: INVALID_STATUS, invalid convertedStatus: Ready to Check: [Status]
Do I need to modify this line? (I’m a newby by the way)
Leadconvert.setConvertedStatus(CLeadStatus.MasterLabel);
Thanks
I am not 100% sure but, I think this could be due to the Status’ not being available for the record types the user has access to / assigned to the lead.
Please use the Debug Log to identify the root cause.
Hi Rakesh, I used this apex code and the test class. I need to access the opportunity id and the account id after conversion. I understand that I will have another variable in the flow that will accept the opportunity id and i can pass it through the getOpportunityId() method. Is there anything else needed for the apex class for the same
You are right Sushmitha. You have to use getOpportunityId() to get the converted id and then use it.
This is cool, I tried it and it worked, I have leads auto converting based on certain criteria… Is there any way that when it converts it can match to an account based on the account website?
I am so glad it helped!
For your requirement, you have to modify Apex class to enforce Duplicate Rule or implement your own logic.
Hi Rakesh, I just want the account to match to another account using the name and not creating a new one. What would I have to add to the above Apex class to make that happen? Is there a way I can do it without modifying the apex class?
Thanks,
What happens in the case, if there is no matching account exist?
If there is no matching account, it will create one, which is fine. The majority of my use case will be around creating a contact and ensuring its added to the account of the same name so we do not have to manually merge it.
Got you.
First, use SOQL query to get the Accounts where Name = Lead.CompanyName, and then You have to write two conditions
If account name does not match
{
Then use same code
}
else
{
modify the exisitg code and use setAccountId(accountId) method to set account ID
}
You have to try something like the following code. This is just a sample code, you may need to modify it
Hi Rakesh,
I tried the code you provided, but had no luck….
I am trying to get this working pretty fast so, I created a text field on lead that I will put the account ID that I want the lead to convert in to – when I try Leadconvert.setAccountId(Convert_to_Account__c); I get the error: Error: Compile Error: Variable does not exist: Convert_to_Account__c at line 11 column 42
I think its obvious I only learning to code and I have looked at several articles and have not had any luck…
My original requirement is still true… I’d love to be able to autoconvert a lead when the website matches the website of an existing account, and that account is of a specific type, else do not thing, and set the contact ownerid to a user defined on the account owners record… but I really need to get these converted quickly, so I am desperate to get the one that works fastest working.
Try something like below code. You do not have to create any custom fields on Lead object
Rakesh, you have no idea how HAPPY I am that you responded so quickly!!! I tried the code and it did work, problem is for reasons beyond my control, we have tons of duplicates…
technically they are not duplicates but branches of the same account, but all may have the same website. I am basically going to export all leads and do some excel work to get leads that I want to auto-convert, then run a mass update (small batch size) to kick off the process that is auto converting the leads…
The thing is that I need the lead to convert to the account that has a matching Type – so even though there are duplicates – only one will have the “type” primary and that is the account I need the lead to convert into…
Additionally I want to add setOwnerId(ownerId) to Account_secondaryowner__c (this is a formula field pulling in the ID of a user)
Is this possible? I’m sorry I am asking so much… I am just learning 🙁
Always happy to help 🙂
Quick questions for you
1. You have created Account_secondaryowner__c on which object? Lead or Account?
2. Do you want to update existing owner to this user (Account_secondaryowner__c)?
I got this much working yay! Account_Type__c=’Primary’ ];
Each account has a secondary owner – and secondary owner is a lookup field on the user record that looks up to user. So on the main account owners user record I have update the lookups with their secondary owners.
Account_secondaryowner__c is a formula field on the Account object that pulls the ID of the secondary owner
Basically the Account is owned by the standard Account owner, and the contacts for that account are owned by the secondary owner.
So: I need – IF lead website = AccountWebsite && Accountype= Primary – on lead update of lead checkbox field “autoconvert” – Run process builder and auto convert those leads to the matching account – and set the contact owner to the account secondary owner… if secondary owner is blank – setcontactowner to dummy user of Id “123” (I guess I could technically set owners through a process on contact…?)
If Account website is null or isnot primary – do not convert but I should hopefully be taking care of that through excel – although technically I would love to have a batch process where if lead customdatefield = Today check the “autoconvert” box – and have that run nightly
PS: I know I am asking for a lot, but you would be my HERO!
As you mentioned earlier Account_secondaryowner__c is a formula field, it is not possible to update this field.
But the workaround is to update the field that you are using to calculate the formula.
For requirement this, if secondary owner is blank – set contact owner to dummy user of Id “123” else update contacts owner to Account_secondaryowner__c (You could use another process)
Always happy to help.
I hate to ask… but I will… How could I setup a batch process to run and it the date matches my date field… check the checkbox… Any help is highly appreciated 🙂
Wait few hours…
Rakesh, thank you so much for posting this! It is super cool that you posted the test class with it. It saved me hours.
Looking forward to more of these types of posts in the future.
Thanks for the kind feedback, Rick! Glad you got it working 🙂
Hi Rakesh,
Great post!
Question, if I set up a web to lead method, will the conversion process you set up work in this scenario?
Thanks!
Glad to hear it!
Yes it should work for Web-to-lead
Great thank you! I will set this up in the next day or so and let you know how it goes.
Let me know how it goes 🙂
Rakesh! Sorry took me so long to get back to you but it worked on the first try! I have a web to lead form setup and it comes in already converted! Thank you for this.
I am glad to know that you were able to resolve this on your own. 🙂
Hi Rakesh,
I’m recieving this error now 🙁
An Apex error occurred: System.DmlException: ConvertLead failed. First exception on row 0; first error: UNKNOWN_EXCEPTION, System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, RollupServiceTest3Trigger: execution of BeforeInsert caused by: line 13, column 45: Dependent class is invalid and needs recompilation: rollupservice: line 87, column 37: Dependent class is invalid and needs recompilation: Class.RollupSummariesSelector: line 62, column 55 RollupSummaries: line 378, column 6: Method does not exist or incorrect signature: Test.isRunningTest(): [] Class.leadconvert.BulkLeadConvert.handleRegularAccountInserts: line 232, column 1 Class.leadconvert.BulkLeadConvert.convertLead: line 90, column 1: []
Any idea what it could be?
Disregard Rakesh. Had nothing to do with your trigger….
How do you prevent duplicates with this method
You can run the OOB Duplicate Rule from Apex.
Hi Rakesh, Do you happen to have the test class for this example? Great example btw
Thanks for the feedback, Rudy! I am glad this was useful!
For test class here you go https://github.com/Rakeshistom/Auto-Convert-Leads/blob/master/TestAutoConvertLeads
Great post! Thanks for this.
How do I use this to convert leads to contacts on existing accounts where DUNS match across both lead and account?
You have change Apex logic to do so.
Hello!
I’m auto converting leads to Contacts on existing accounts that have a matched D-U-N-S. I have a flow built out to loop through and find a matched account and then assigns a variable, how do I use this account ID variable {!SobjAccountwithMatchedDuns.Id} in this lead convert Class?
Or would it be easier to just modify this code to do all of it?
Thanks!
As soon as Contacts gets created, use one Process Builder to find Account with matched D-U-N-S and the update it.
Hi,
I have visual force page embedded in Lead page layout. Upon conversion its showing :Record type unavailable error.
I have default record types in place for all objects and also person account is enabled. So i am thinking the error is due to VF page in lead layout, I am correct? Do you know any workaround for the error.
Thanks a ton!
Thanks so much for this! Another internal client satisfied, thanks to you!!
Glad to know 🙂
Hiya, we’ve implemented this solution, and it works great for newly created leads, but for updating leads it seems to cause an error.
We get:
The record couldn’t be saved because it failed to trigger a flow. A flow trigger failed to execute the flow with version ID 301260000009Tap. Contact your administrator for help.
This only happens with previously created leads, not with new leads. We have set up the process builder workflow to trigger on a checkbox being ticked.
Any help appreciated.
Tom and Cassio
Email me process and code at info@autoamtionchampion.com
Hi Rakesh,
Thank you for the solution but i am receiving error on editing the lead record as :
Workflow Action Failed to Trigger Flow
The record couldn’t be saved because it failed to trigger a flow. A flow trigger failed to execute the flow with version ID 301p00000001Xun. Flow error messages: <b>An unhandled fault has occurred in this flow</b><br>An unhandled fault has occurred while processing the flow. Please contact your system administrator for more information. Contact your administrator for help.
I am using exact same code and process builder as per your instructions…..Please let me know what am i doing wrong?
Please use Debug Log or Error Email you’ve received from Salesforce to find the actual issue. Else post those screenshots here
Hi Rakesh,
Error seems due to record type assignment :- UNAVAILABLE_RECORDTYPE_EXCEPTION, Unable to find default record type: []
( FYI In my sandbox person account is enabled ) When user with particular profile tries to update a field on which AutoConvertLeads class is to be invoked he gets above error.
Profile record type assignment screen shot : http://www.imageno.com/yhjm19p01dzxpic.html
Hi Rakesh,
I am getting error :– UNAVAILABLE_RECORDTYPE_EXCEPTION, Unable to find default record type: []
We have person account enabled and default person account record type selected for the profile using which i am testing..
Let me try in my dev org where Person Account is enabled.
Hi Rakesh,
issue is solved now.. Actually in my case “company” field had a value (but was hidden in layout) and business record type was disabled….which is why record type unavailable error was shown.
Thanks for the reply though.
Glad you were able to sort it out 🙂
I’m trying to use this in Lightning and while it does convert, I get an error when the page refreshes that the lead has already been converted. What would I need to add to redirect to the opportunity page that was created upon conversion? Thanks in advance!
Let me try it
This known issue for this, https://success.salesforce.com/issues_view?id=a1p30000000eVsBAAU
Hi Rakesh,
I tried your method. I am getting the following error from the process builder
An Apex error occurred: System.DmlException: ConvertLead failed. First exception on row 0; first error: INVALID_CROSS_REFERENCE_KEY, valid leadId is required: []
Also I am have a business process that creates person account and opportunity once the lead is converted
Any suggestions will be vary valuable.
thank you
Make sure that you are passing correct record id
This is fantastic!! Thank you.
Thank you!
I’m very excited to implement this. I went through the process you laid out and when testing I received the following errors. Any insight?
An error occurred at element myRule_1_A1 (FlowActionCall).
An Apex error occurred: System.DmlException: ConvertLead failed. First exception on row 0; first error: INVALID_CROSS_REFERENCE_KEY, valid leadId is required: []
Can you send me the complete screenshot of your flow and Process Builder at info@automationchampion.com
Thank you for your response! I think we’ve gone a different direction for now. I’ll let you know if we decide to implement. I really appreciate what you’ve done!
Hi,
After implementing leads can not convert error is CANNOT_UPDATE_CONVERTED_LEAD, could you help me with some solution?
You can’t update converted Lead.
Hi
Are these records automatically assigned to the owner of the lead? What if we wanted to auto-assign the lead creation to a certain individual? Or how about auto-associate to an existing account?
Customize Apex logic as per your business use case 🙂
Great post, Rakesh, really helpful!
I have implemented this in my organization and it works as expected 🙂
I just have a question regarding it, does it work for mass conversions? When converting several leads at a time it seems to convert only one of them but does nothing with the others. Is there something that can be done to make it work for several leads at a time?
Thanks!
Please check out the new bulkified Apex Class
That is really good, do I need to do something special in order to test the method with @InvocableMethod annotation?
and personal question, do you believe there is any advantages in using the process builder instead of triggering this from a trigger?, I am just asking this as I am having some issues with process builder when trigger from a bulk upload/edit, unless this bulk upload is done 1 by 1
its because of
and is there any way to adapt this process for mass conversions? If I change the code to a limit different from 1 it generates an error message, so I can only convert leads one by one.
Thanks!
Please check out the new bulkified Apex Class
This is so helpful! Thanks.
And in case I need to run this automatic conversion for several leads at a time, is there any tweak to your code that allow me to do that?
This is amazing, superstar, thanks so much appreciate this Rakesh.
Thank you 🙂