function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Nicky TorstenssonNicky Torstensson 

How Do You Test LeadConvert, When In UI Selecting Existing Contact, But New Account Should Be Created

Hi

How do you test the Lead Convert where you have selected the following from the UI:
  • New account should be created
  • Existing contact is selected
  • No opportunities
The documentation states, that you can use LeadConvert.setConvertedContactId, but then you have to set the ConvertedAccountId to be the same - but this contradicts what my use case is.
public static testMethod void myTest(){
        Contact existingContact = TestUtil.createContact(true);

        Lead ld = TestUtil.createLead(false);
        ld.FirstName = 'FirstName';
        ld.LastName = 'LastName';
        ld.ContactPersonFirstName__c = 'NOT FirstName';
        ld.ContactPersonLastName__c = 'NOT LastName';
        insert ld;

        Database.LeadConvert lc = new Database.LeadConvert();
        lc.setLeadId(ld.id);
        LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true LIMIT 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);
// This is where I chose the existing contact, but as I want a new account created, then I do not specify an account id
        lc.setContactId(existingContact.Id); 

        Test.startTest();
        Database.LeadConvertResult lcr = null;
        User testUserContext = TestUtil.getTestContextUser(true);
        System.runAs(testUserContext) {
// Here is fails
            lcr = Database.convertLead(lc); 
        }
        Test.stopTest();
I get the error: System.DmlException: ConvertLead failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, accountId must be specified if contactId is not null: [Id]
Best Answer chosen by Nicky Torstensson
Alain CabonAlain Cabon
Hi Nicky,

The workaround is to change the AccountId of the existing Contact twice (with all the possible effects).
  1. One update of accountId into existingContact before the Database.convertLead(lc); because accountId =new_company.Id is required indeed
  2. One update of accountId into existingContact after the Database.convertLead(lc);  because you want to preserve the previous link.

Account new_company = new Account(name =ld.Company);
insert new_company;

Account existingCompany = new Account(name ='lulu');
insert existingCompany;
        
Contact existingContact = new Contact(FirstName='titi',lastname='toto', accountId=new_company.Id);
insert existingContact;

....

lcr = Database.convertLead(lc);  
        
if (!lcr.isSuccess()) {
    delete new_company;
}
         
existingContact.AccountId = existingCompany.Id;
update existingContact;

That works at the end as expected but it is a series of workarounds and the double changes of AccountId for the existing contact could be problematic in some cases ( irreversible processes ).

It should be interesting to test another forum ( stackexchange ) with the same question which seems a basic case for the conversion of leads in order to know if they also use these kind of workarounds because of the strong contrainsts in Apex code.

https://salesforce.stackexchange.com/

 

All Answers

Alain CabonAlain Cabon
Hi,

Did you try this?
 
 Lead ld = TestUtil.createLead(false);
 ld.FirstName = 'FirstName';
 ld.LastName = 'LastName';
 ld.Company='Nicky Torstensson And Sons';
 ld.ContactPersonFirstName__c = 'NOT FirstName';
 ld.ContactPersonLastName__c = 'NOT LastName';
 insert ld;

Even if I don't know if you have "sons".

 
Nicky TorstenssonNicky Torstensson
Hi Alain
Thanks for looking into it. However, the issue does not lie in the missing (required) field Company. The TestUtil class creates the lead properly.
The issue lies in testing the lead convert, where you choose an existing contact (see below screenshot for clarity), but choose a new account to be created
User-added image
Alain CabonAlain Cabon
Hi,

I you add  ld.Company='Nicky Torstensson And Sons';  that will create the account from the lead.

I made the tests and that works fine.

You must choose at least the name of the new account in  the lead.
Nicky TorstenssonNicky Torstensson
Hi Alain
The TestUtil Class sets the value of Company = 'Test Company';. This is not where the issue lies.

Please note, the issue is not about creating the lead, it comes at the 3 line from the bottom of my sample code. Have you been able to test that line?
Alain CabonAlain Cabon
What are the required fields for your account?

The basic code below works fine in a free developer org:
 
@isTest
public class LeadConversionTest {
    public static testMethod void myTest(){
        Contact existingContact = new Contact(FirstName='titi',lastname='toto');
        
        Lead ld = new Lead();
        ld.FirstName = 'FirstName';
        ld.LastName = 'LastName';
         ld.Company='Fry And Sons';
        insert ld;
        
        Database.LeadConvert lc = new Database.LeadConvert();
        lc.setLeadId(ld.id);
        LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true LIMIT 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);
        // This is where I chose the existing contact, but as I want a new account created, then I do not specify an account id
        lc.setContactId(existingContact.Id); 
        
        Test.startTest();
         // The account doesnt exist yet.
        System.assertEquals(0,[select count() from account where name = 'Fry And Sons' ]);
        Database.LeadConvertResult lcr = null;
        //   User testUserContext = TestUtil.getTestContextUser(true);
        //   System.runAs(testUserContext) {
        lcr = Database.convertLead(lc); 
        // the account is created after the lead conversion
        System.assertEquals(1,[select count() from account where name = 'Fry And Sons' ]);
        System.assertNotEquals(null,[select id from account where name = 'Fry And Sons' ][0].Id);
        
        //    }
        Test.stopTest();
    }
}

The account is well created with the name 'Fry And Sons'

 
Alain CabonAlain Cabon
Ok,  that works for me because the contact was not created above indeed.

 Contact existingContact = new Contact(FirstName='titi',lastname='toto');
 insert existingContact;

My case is different.
Alain CabonAlain Cabon
So you cannot use lc.setContactId(existingContact.Id);  if you want a new account and you need to map the missing fields with new lines of code probably.
Nicky TorstenssonNicky Torstensson
Hi Alain.

This was also the conclusion I came to via the link to the documentation in my original post.
And to your response "If you want a new account and you need to map the missing fields with new lines of code probably.", I agree, but how? This is what my question is about.
Alain CabonAlain Cabon
Hi Nicky,

A simple work-around is to create a new account with the required fields equals to the existing fields in the lead (here Account.Name)
 
@isTest
public class LeadConversionTest {
    public static testMethod void myTest(){
        
        Lead ld = new Lead();
        ld.FirstName = 'FirstName';
        ld.LastName = 'LastName';  
        ld.Title = 'Dr';
        ld.Company='Fry And Sons';
        ld.CompanyDunsNumber='123456';
        ld.City='Paris';
        insert ld;
        
        Account new_company = new Account(name =ld.Company);
        insert new_company;
        
        Contact existingContact = new Contact(FirstName='titi',lastname='toto', accountId=new_company.Id);
        insert existingContact;
        
        Database.LeadConvert lc = new Database.LeadConvert();
        lc.setLeadId(ld.id);
        lc.setDoNotCreateOpportunity(true);
        LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted = true LIMIT 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);
        
        lc.setContactId(existingContact.Id);
        lc.setAccountId(new_company.Id);
        
        Test.startTest();
        System.assertEquals(1,[select count() from account where name = 'Fry And Sons' ]);
        Database.LeadConvertResult lcr = null;
        
        lcr = Database.convertLead(lc);  
        
        if (!lcr.isSuccess()) {
            delete new_company;
        }
        
        System.assertEquals(existingContact.Id, lcr.getContactId());
        
        Account acc2 = [select name,billingcity,DunsNumber from account where id=:lcr.getAccountId()];
        System.assertEquals(acc2.BillingCity,'Paris');  // come from the lead
        System.assertEquals(acc2.DunsNumber,'123456');  // come from the lead
        System.assertEquals(acc2.Name, 'Fry And Sons');
        System.assertEquals(1,[select count() from account where name = 'Fry And Sons' ]);
        System.assertEquals(new_company.Id,[select id from account where name = 'Fry And Sons' ][0].Id);
        
        Contact cnt2 = [select FirstName, LastName , Title from contact where id=:lcr.getContactId()];
        System.assertEquals(cnt2.FirstName,'titi');
        System.assertEquals(cnt2.LastName,'toto');
        System.assertEquals(cnt2.Title,'Dr');  // come from the lead
        System.assertEquals(lcr.getContactId(),[select id from contact where firstname = 'titi' and lastname = 'toto'][0].Id);
        
        Test.stopTest();
    }
}

The problem is to delete new_company is the conversion failed at least.

 
Alain CabonAlain Cabon
The problem is to delete new_company if the conversion failed at least (typo)
Nicky TorstenssonNicky Torstensson
I understand that you are using a dummy account, but if the lead convert result is successful, then would you not want to delete the dummy account and continue with a new account? Specifically I am referring to these 3 lines of your code (the *!*)
if (!lcr.isSuccess()) {
            delete new_company;
        }
Also, the lead conversion does not create 2 accounts. If you have already set the account you convert to by setConvertedAccountId, then another one will not be created.

To understand my business rationale: Upon lead convert I am updating account contact relations (specifically the roles), based on lead fields. Hence if I choose an existing contact, I still want a new account to be created, but the existing contact gets a role (AccountContactRelation) assigned to the new account, but has it's Primary Account (the Contact.AccountId) unchanged.
 
Alain CabonAlain Cabon
"!" the exclamation mark is the logical negation.

if (!lcr.isSuccess()) { delete new_company; }

.. means "if the conversion is unsuccessful then delete the new_company."

It is not a "dummy' company. At the end of the process, you want a new company but you can create it at first like above.

The only contrainsts is to create the new account with the exact same values (when they are required) as the lead uses, here the "name") because these fields are not overriden during the lead conversion.
Nicky TorstenssonNicky Torstensson
Hi Alain

But then it does not fit my request. I want the lead to be converted to an existing contact (which of course is related to an existing account) and to a new account. The test will not simulate this - on the contrary, it simulates that upon convert I select an existing account and contact (with them being related to each other.
Alain CabonAlain Cabon
Hi Nicky,

The workaround is to change the AccountId of the existing Contact twice (with all the possible effects).
  1. One update of accountId into existingContact before the Database.convertLead(lc); because accountId =new_company.Id is required indeed
  2. One update of accountId into existingContact after the Database.convertLead(lc);  because you want to preserve the previous link.

Account new_company = new Account(name =ld.Company);
insert new_company;

Account existingCompany = new Account(name ='lulu');
insert existingCompany;
        
Contact existingContact = new Contact(FirstName='titi',lastname='toto', accountId=new_company.Id);
insert existingContact;

....

lcr = Database.convertLead(lc);  
        
if (!lcr.isSuccess()) {
    delete new_company;
}
         
existingContact.AccountId = existingCompany.Id;
update existingContact;

That works at the end as expected but it is a series of workarounds and the double changes of AccountId for the existing contact could be problematic in some cases ( irreversible processes ).

It should be interesting to test another forum ( stackexchange ) with the same question which seems a basic case for the conversion of leads in order to know if they also use these kind of workarounds because of the strong contrainsts in Apex code.

https://salesforce.stackexchange.com/

 
This was selected as the best answer