+ Start a Discussion
chriseustacechriseustace 

Trigger to convert lead to account/contact/oppty

Does anyone know how I'd go about creating a trigger to convert a lead to an account contact and oppty, based upon a field in the lead?  For example, A lead score of > 30, I'd like to trigger the lead to automatically convert, and kick off a notification email. 

 

Has anyone done this before?

 

Thanks!

Chris

learnSFlearnSF

I was doing using s-control button.

 

When user hit buttton that elad convert in to Account. Here is code fro s-control with ajax toolkit but you can use apex with same method for lead convert.

 

// run the convert var leadCons = new sforce.LeadConvert(); leadCons.leadId = "{!Lead.Id}"; leadCons.ownerId = document.getElementById('owner_id_lkid').value; leadCons.convertedStatus = document.editPage.cstatus.value; leadCons.doNotCreateOpportunity = document.editPage.nooppti.checked; if(leadCons.doNotCreateOpportunity=="false") leadCons.opportunityName = document.editPage.noopptt.value; leadCons.overwriteLeadSource = new Boolean(false); // default this if ( document.getElementById("accountPickList").value != "" && document.getElementById("accountPickList").value != "000000000000000" ) { // for existing account of this name leadCons.accountId = document.getElementById("accountPickList").value; } if ( document.getElementById("contactPickList").value != "" && document.getElementById("contactPickList").value != "000000000000000" ) { // for existing account of this name leadCons.contactId = document.getElementById("contactPickList").value; } var lc = sforce.connection.convertLead([leadCons]); //if ( lc[0].className != "LeadConvertResult" ) { // throw ("<pre>sforceClient.ConvertLead() " + lc[0].toString() + "</pre>" ); // } if (!(lc[0].getBoolean("success"))) { alert("lead convert failed " + lc[0]); throw ("could not convert lead " + "{!Lead.Id}" + document.editPage.noopptt.value + "<br>" //+ lc[0].errors[0].message );

 

logic will be same only syntex will be different.

 

Hope this helps.

chriseustacechriseustace

ok, that seems like it sort of make sense.  Can anyone help me with the syntax of the trigger?

 

Any help is appreciated!  Thanks!

 

Chris

chriseustacechriseustace

I've started the trigger, any advice?

 

trigger LeadCampaignLinkTrigger on Lead (after update) {
Lead myLead = trigger.new[0];
if (myLead.LeadScore__c > 10) {
var Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(lead.Id);
}
}

chriseustacechriseustace

getting closer:

 

trigger ConvertLead on Lead (after update) {
Lead myLead = trigger.new[0];
if (myLead.Lead_Score__c > 10) {
Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(myLead.Id);
    update myLead;
}// else nothing
}
 
Problem is, I'm getting the error: 

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger ConvertLead caused an unexpected exception, contact your administrator: ConvertLead: execution of AfterUpdate caused by: System.SObjectException: DML statment cannot operate on trigger.new or trigger.old: Trigger.ConvertLead: line 6, column 5

dmchengdmcheng

You cannot run an Update on the same set of records that the trigger is running on.  Your myLead may look like an independent object, but simplistically speaking it's just an alias or shortcut back to Trigger.new, hence the error detail.

 

You shouldn't need to do any kind of manual update anyway since the LeadConvert process should take care of any changes to the Lead record to reflect the conversion.

 

Also, your trigger is not "bulkified" as most Apex code should be.  Check the Apex documentation, tutorials, forum postings and web presentations for how to write bulk triggers and other Apex best practices.

jkucerajkucera

The API docs have the best examples, but note the syntax is slightly off as this is java, not apex.  Note you should set the AccountID, ContactID, and OpptyID before convert:

 

 

private Boolean convertLead (String leadId, String contactId, String accountId, boolean overWriteLeadSource, boolean doNotCreateOpportunity, String opportunityName, String convertedStatus, boolean sendEmailToOwner) { LeadConvert leadConvert = new LeadConvert(); leadConvert.setLeadId(new ID(leadId)); leadConvert.setContactId(new ID(contactId)); leadConvert.setAccountId(new ID(accountId)); leadConvert.setOverwriteLeadSource(overWriteLeadSource); leadConvert.setDoNotCreateOpportunity(doNotCreateOpportunity); leadConvert.setOpportunityName(opportunityName); leadConvert.setConvertedStatus(convertedStatus); leadConvert.setSendNotificationEmail(sendEmailToOwner); LeadConvertResult[] lcr = null; try { lcr = binding.convertLead(new LeadConvert[] {leadConvert}); for (int i=0; i<lcr.length; i++) { if (lcr[i].isSuccess()) { System.out.println("Conversion succeeded.\n"); LeadConvertResult result = lcr[i]; System.out.println("The new contact id is: " + result.getContactId()); } else { System.out.println("The conversion failed because: " + lcr[i].getErrors(0).getMessage()); } } } catch (UnexpectedErrorFault e) { System.out.println("Unexpected error encountered:\n\n" + e.getExceptionMessage()); return false; } catch (RemoteException e) { System.out.println("Remote exception encountered:\n\n" + e.getMessage()); return false; } return true; }

 http://www.salesforce.com/us/developer/docs/api/index.htm


 

AshishTomarAshishTomar

You should take advantage of our "Mass & Auto Convert Leads" application.

 

Appexchange Link

 

 

https://sites.secure.force.com/appexchange/listingDetail?listingId=a0N300000030ptZEAQ

Message Edited by AshishTomar on 03-12-2010 05:30 PM
Money.ax731Money.ax731

My code has 69% coverage need help for deployment
My code has 69% coverage. I need at least 75%. I am stuck at the very last step. Please help asap since I need to deploy this code.

Any help would be wonderful.

Based on the lead type i am trying to populate the Channel Partner Account or the End Customer Account which needs to be copied from the account name field of opportunity on Lead Convert.

 

I have the apex class below till where it converts the lead but I am trying to query the converted opportunity.


Both Trigger and Apex Class are pasted below.

Almost there at 69% coverage

trigger LeadConvertAccountNameType on Lead (before update) {
system.debug('trigger size is: ' + trigger.size);
system.debug('converted opp id is: ' + trigger.new[0].ConvertedOpportunityId);
system.debug('lead RT id is: ' + trigger.new[0].RecordTypeID);
if( trigger.isUpdate && trigger.new.size() == 1 && trigger.new[0].ConvertedOpportunityId != NULL) {

      if (trigger.new[0].IsConverted && trigger.new[0].RecordTypeID == '01280000000Ln1Y') {          
       // Assign the value from the Account Name "Status" field to the Channel Partner Name "Type" field  
                Opportunity opp = [SELECT Id, AccountId FROM Opportunity WHERE Opportunity.Id = :trigger.new[0].ConvertedOpportunityId];
                opp.Channel_Partner_Account__c = opp.AccountId;
                system.debug('assigning channel partner');   
                update opp;       
       } else if (trigger.new[0].IsConverted && trigger.new[0].RecordTypeID == '01280000000Ln1d') {
                Opportunity opp = [SELECT Id, AccountId FROM Opportunity WHERE Opportunity.Id = :trigger.new[0].ConvertedOpportunityId];
                opp.End_Customer_Account__c = opp.AccountId;
                system.debug('assigning end user account');
                update opp;
       }
    }
}


Class

public class TestLeadConvertAccountNameType{
       
        static testMethod void test() {
       
                   
                   
              
            Lead l = new Lead();
            l.LastName = 'CRM Testing INC';
            l.Company = 'CRM Testing INCtest';
            l.city = 'test';
            l.street = 'test';
            l.state = 'CA';
            l.country = 'United States';
            l.status = 'Qualified Lead';
            l.sub_status__c = 'Bad Phone';
            l.RecordTypeId = '01280000000Ln1Y';
            l.OwnerId = '00580000003TJmH';
            l.Product_interest__c = 'NAS';
            l.Lead_Type__c = 'Distribution';
            l.email = 'test@testnetgear.com';
            insert l;
           
         
   
   
   
   
        Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(l.id);
        LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);
        if(l.Lead_Type__c == 'Distribution' || l.Lead_Type__c == 'End User'){
        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());
        Id oppId1 = lcr.getOpportunityId();
        system.debug('opp id is: ' + oppId1);
        system.debug('opp id is: ' + lcr.getopportunityId());
       
       
           I need something here to make the coverage go to 75%. How do I validate the opportunity is where i am stuck!!
          
        }
        else{
        l.addError('Lead cannot be converted without Product Selection !');
        l.addError('Please Select Atleast One Product');
        }
       
    }
   
         

                    
}

jkucerajkucera

Remove your system.debug's (or comment them out) and your coverage should be high enough.  I'm pretty sure they don't get "run" during the tests.

CalebECalebE

Hello,

 

Could you post your final apex code for your auto conversion trigger?

 

Thanks,

chriseustacechriseustace

sure thing:

 

trigger LeadConvert on Lead (after insert,after update) {
//Bulkified
List<String> LeadNames = new List<String>{};
for(Lead myLead: Trigger.new){
 if((myLead.isconverted==false) && (myLead.ProfileStatus__c == 'Paid profile')) {
Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(myLead.Id);
        lc.convertedStatus = 'Qualified';
        //Database.ConvertLead(lc,true);
        lc.setDoNotCreateOpportunity(true);
        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());
        }
        }
}

trigger LeadConvert on Lead (after insert,after update) {
//BulkifiedList<String> LeadNames = new List<String>{};for(Lead myLead: Trigger.new){ if((myLead.isconverted==false) && (myLead.ProfileStatus__c == 'Paid profile')) {Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(myLead.Id);        lc.convertedStatus = 'Qualified';        //Database.ConvertLead(lc,true);        lc.setDoNotCreateOpportunity(true);        Database.LeadConvertResult lcr = Database.convertLead(lc);        System.assert(lcr.isSuccess());        }        }}

 

CalebECalebE

Thank you - that worked like a champ.  Do you know how I could get the contact to be created to an existing account?

goabhigogoabhigo

If I am not wrong your trigger is fired when ProfileStatus__c = Paid Profile. I mean you don't click 'Convert' button.

 

Can you help me to write a trigger that is called only when 'Convert' button is clicked?

jkucerajkucera

@Abhi - use isConverted=TRUE to get leads that are converted:

 

 

trigger onLeadConverts on Lead (before update){

  for (Lead l: trigger.new){
    if(l.isconverted=TRUE){
       //do stuff
    }
  }
}

 

 

CalebECalebE

Anyone know how I can get an autoresponse to fire when a trigger fires that converts a lead after it is inserted?  I was trying to use a workflow rule to update a field that would then fire the conversion trigger, but am getting the following error:

 

Alert: Salesforce.com experienced the following problem creating the lead below:

Reason: common.apex.runtime.impl.TriggerExecutionException: Apex trigger LeadConvert caused an unexpected exception, contact your administrator: LeadConvert: execution of AfterUpdate

caused by: System.DmlException: ConvertLead failed. First exception on row 0; first error: UNKNOWN_EXCEPTION, System.DmlException: Update failed. First exception on row 0 with id 00QA000000H3WixMAF; first error: CANNOT_UPDATE_CONVERTED_LEAD, cannot reference converted lead: []

 

Thank you,

goabhigogoabhigo

Hi John,

 

I did as u told. But got the following error message:

Error: System.DmlException: Update failed. First exception on row 0 with id 00QO0000001749HMAQ; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, ConvertLeadSMS: execution of BeforeUpdate caused by: System.DmlException: ConvertLead failed. First exception on row 0; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 00QO0000001749H) is currently in trigger ConvertLeadSMS, therefore it cannot recursively convert itself: [] Trigger.ConvertLeadSMS: line 11, column 46: [] (System Code) External entry point

 

This is my trigger code:

trigger ConvertLeadSMS on Lead (before update) {
    
    for(Lead myLead: Trigger.new){
        List<SMS__c> lstSms = [select To_Lead__c,To_Contact__c from SMS__c where To_Lead__c=:myLead.Id];
        if((myLead.isConverted==true)) {
            System.debug('### INSIDE IF');
            System.debug('### lstSms: ' + lstSms);
            Database.LeadConvert lc = new database.LeadConvert();
            lc.setLeadId(myLead.Id);
            lc.convertedStatus = 'Qualified';
            Database.LeadConvertResult lcr = Database.convertLead(lc);
            for(Integer i=0;i<lstSms.size();i++) {
                lstSms[i].To_Contact__c = lcr.getContactId();
                lstSms[i].To_Lead__c = '';
            }
            System.debug('### After update');
        }
    }
}

 

My aim is to attach the SMS records of the leads to Contacts on conversion. Hence the code-lstSms[i].To_Contact__c = lcr.getContactId();

 

Please suggest me to get this done.

jkucerajkucera

You can't convert a lead that's already converted. The code fires only for leads that are converted, and you are trying to convert it again:

            Database.LeadConvertResult lcr = Database.convertLead(lc);

 

Also, any DML actions such as this will cause the same trigger to fire, so you'll get a recursion error even for leads that aren't converted.  

 

It's probably easier to create a before insert contact trigger to add the SMS records - get lead id's where lead.convertedContactId matches the contact in question.  

goabhigogoabhigo

I tried that too. Here is my code

 

 

trigger TranferLeadSMS on Contact (before insert) {
    for(Contact c: Trigger.New) {
        Lead lObj = null;
        lObj = [select l.Id,l.convertedContactId from Lead l where l.convertedContactId=:c.Id][0];
        System.debug('### lObj: ' + lObj);
        if(lObj != null) {
            System.debug('### INSIDE IF 1');
            List<SMS__c> lstSms = [select To_Lead__c,To_Contact__c from SMS__c where To_Lead__c=:lObj.Id];
            System.debug('### lstSms: ' + lstSms);            
            if(lstSms.size() !=0) {
                System.debug('### INSIDE IF 2');
                for(Integer i=0;i<lstSms.size();i++) {
                    lstSms[i].To_Contact__c = c.Id;
                    lstSms[i].To_Lead__c = null;
                }
            update lstSms;
            System.debug('### After update');
            }
        }
    }
}

 

 

This doesn't work. Conversion is done. But SMS records are not found in Contacts[ I saw the log file. It shows c.id=null, thats why lObj contains a different lead which is not converted. So whenever trigger is fired, same Lead is found in lObj. Hence lstSms is not updated].

 

If I change trigger to After Insert, C.id has some value. But lObj is null(it has no matches).

 

Please suggest me. 

 

 

 

 

dgonzalezdgonzalez

I'm also having troubles with this!

 

Here is my simple trigger code:

 

 

trigger automaticConvert on Lead (after insert, after update) {

    // no bulk processing; will only run from the UI
    if (Trigger.new.size() == 1) {
        
        // verify conditions for automatically convert this lead
        if (((Trigger.new[0].FirstName != '' && Trigger.new[0].FirstName != null &&
                Trigger.new[0].LastName != '' && Trigger.new[0].LastName != null)) &&
                ((Trigger.new[0].Phone != '' && Trigger.new[0].Phone != null) || 
                (Trigger.new[0].Fax != '' && Trigger.new[0].Fax != null) || 
                (Trigger.new[0].Email != '' && Trigger.new[0].Email != null))) {
            
            Database.LeadConvert lc = new database.LeadConvert();
            lc.setLeadId(Trigger.new[0].Id);
            
            LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1];
            lc.setConvertedStatus(convertStatus.MasterLabel);

            Database.LeadConvertResult lcr = Database.convertLead(lc);
            System.assert(lcr.isSuccess());
        }
    }
}

 

 

When I try inserting or updating a lead (and including an Email and FirstName and LastName) I get this error:

 

Apex trigger automaticConvert caused an unexpected exception, contact your administrator: automaticConvert: execution of AfterUpdate caused by: System.DmlException: ConvertLead failed. First exception on row 0; first error: UNKNOWN_EXCEPTION, System.DmlException: Update failed. First exception on row 0 with id 00QS00000054JkUMAU; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, automaticConvert: execution of AfterUpdate caused by: System.DmlException: ConvertLead failed. First exception on row 0; first error: CANNOT_UPDATE_CONVERTED_LEAD, cannot reference converted lead

 

Please, help

jkucerajkucera

dgonzalez - you can't convert a lead in a trigger as it will give you a recursion error. You need to do convert in another apex class that's called either from a visualforce button, or an @future method call from within a trigger.  If you do the @future call, you need a variable to track whether the method has already been called to prevent a recursion error (can't call an @future method from another @future method).

 

btw-what does your trigger do that the generic lead convert button doesn't do?

jkucerajkucera

Abhi - note your code will break quickly due to the query governor limit so you'll want to do your lead and SMS__C queries outside of hte loops.  

 

In your list, you need to match the converted leadID to the SMS record and grab the right convertedContactId to add to the SMS record - you'll want to store these in maps to avoid governor limits.

 

You can't update the lead field to null after the lead is converted, so you'll want to remove this line:

lstSms[i].To_Lead__c = null;
dgonzalezdgonzalez

Thanks jkucera!

 

That helped!

 

The problem was a recursion error.

 

Actually I solved the problem adding this validation:

 

 

if (Trigger.new[0].isConverted == false) {

 

 

kungkekekungkeke

Hi I not all too familiar with coding - that's why I'm on here trying to find a way to write a trigger to mass convert leads (w/o oppt. but that's a detail).

 

The code chriseustace provided works fine in my sandbox, however I just can't seem to get it deployed to production since the code coverage is not enough and I can't get a test to work.

 

So, does anyone have a test that could get this code to fly?

Mayank_JoshiMayank_Joshi

Hi CalebE ,

 

I have been doing the exact same thing but continously recieving following error :

 

FATAL_ERROR|System.DmlException: ConvertLead failed. First exception on row 0; first error: INVALID_STATUS, invalid convertedStatus: Qualified: []

 

 I am not sure as this trigger is compiled successfully .As  I want to create Opportunity as well so I commented out "lc.setDoNotCreateOpportunity(false); " this statement .

 

And under If statement I made changes " if((myLead.isconverted==false) && (myLead.Status == 'Open - Not Contacted'))  " .

 

Below is the complete trigger :

 

trigger LeadConvert on Lead (after insert,after update) {
for(Lead myLead : Trigger.new)
  {
   if((myLead.isconverted==false) && (myLead.Status == 'Open - Not Contacted'))
     //if((myLead.isconverted==false))
   {
    Database.LeadConvert lc = new database.LeadConvert();
    lc.setLeadId(myLead.Id);
    //lc.setconvertedStatus = 'Qualified';        //Database.ConvertLead(lc,true); 
    lc.setConvertedStatus('Qualified');
    //lc.setDoNotCreateOpportunity(false);  
    Database.LeadConvertResult lcr = Database.convertLead(lc);
    System.assert(lcr.isSuccess());     
   }
  }
}

 

Can you help me out ?

 

Thanks ,

CalebECalebE

Hello,

 

I am not an expert, but I would check the set up of your Lead Status field to make sure you've designated "Qualified" as a converted status.

 

I hope that helps,

 

Caleb

Mayank_JoshiMayank_Joshi

No worries CalebE And BTW thanks for looking into my issue once gain ,

 

I am now able to convert lead using Convert lead() Method . I am posting my trigger just in case if some body need this :

 

trigger ConvertLead on Lead (after insert, after update) {

    for (Lead lead : Trigger.new) {
      if (lead.isConverted == false) //to prevent recursion

      {
       
        Database.LeadConvert lc = new Database.LeadConvert();
        lc.setLeadId(lead.Id);
       
        String oppName =  lead.Name;
        lc.setOpportunityName(oppName);
       
        LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);
       
        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());
       
             
    }
  }
}

 

Regards,

chriskim757chriskim757
Will this create a duplicate account?
Danielle Pulley 10Danielle Pulley 10
I used the Trigger above and it does work. How should modify it to only convert on Lead Source = "Academy Registration", "Organization Registration" and "User Registratrion"?  Also, needs to include not converting to a lead. Only Account and Contact. 
suvarna Reddysuvarna Reddy
i am new in saleforce..please help me..
On Lead Trigger 
* Check for duplicate Lead (Name, Email and Phone)
* If mathes with lead then merge. (consider limit here search for workaround)
* If matches with contact then convert it.