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
Roger WickiRoger Wicki 

Web To Lead Trigger

Hi folks

I created a Lead trigger after insert, that should search for Contacts with the same Email address as the lead and update a field depending on a lead field.

More detailed:
We use a Web-To-Lead Form to create Leads for people who would like to unsubscribe for one of our two newsletters we send. Because creating Records over this form is by far the easiest way (no VF pages), we had a go for that. We adapted the web-to-lead form to a simple link which creates a lead and redirects to a chosen website. The link contains the Org Id, the Lead Record Type Id and a value to fill the picklist "OptOutType" in which we store for what newsletter the user wants to unsubscribe.


My test class executes fine without any (unwanted) errors. However, when using the web to lead link, there's only a lead created but no update on contact. That is when I thought that maybe the code somehow runs using access restrictions and tried to run the code as admin user, but then the lead wasn't even created anymore.

Because the Web To Lead process isn't run by any existing user, I can not use the Debug Log option from the SF setup as there is nobody to track. That leaves me clueless on how to catch the error message...



I use a trigger template with trigger handler classes fro all of my code. On that just a few notes:
- Trigger runs on every DML operation
- Trigger calls the TriggerManager class and adds an instance of a handler class and passes on the type of DML operation
- Trigger calls the methods "setValues(trigger.new, trigger.old.map)" and "handle(dmlOperation)".
- The handler class implements the triggerTempalte interface which makes it execute the two methods mentioned before

And here is my handler class:

public class LeadHandlerNewsletter implements TriggerTemplate.Handler
{
private list<Lead> newLeads;
private list<RecordType> recTypes;
private map<String, Id> recTypeMap = new map<String, Id>();
private User owner = new User();

public void setValues(list<SObject> newValues, map<Id, SObject> oldValues)
{
newLeads = newValues;
recTypes = [ SELECT Id, Name FROM RecordType WHERE SObjectType = 'Lead' ];
for ( RecordType rec : recTypes )
{
recTypeMap.put(rec.Name, rec.Id);
}
owner = [ SELECT Id FROM User WHERE CustomApexErrorReceiver__c = true AND isActive = true LIMIT 1 ];
if ( owner == NULL || Test.isRunningTest() )
{
Profile admin = [ SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1 ];
owner = [ SELECT Id FROM User WHERE ProfileId = :admin.Id AND isActive = true LIMIT 1 ];
}
}

public void handle(TriggerTemplate.TriggerAction theAction)
{
if ( theAction == TriggerTemplate.TriggerAction.afterInsert )
{
processRelevant(findRelevant(newLeads, recTypeMap));
}
}

private static list<Lead> findRelevant(list<Lead> allLeads, map<String, Id> recTypeMap)
{

list<Lead> relLeads = new list<Lead>();
 
try
{
for ( Lead currLead : allLeads )
{
if ( currLead.RecordTypeId == recTypeMap.get('Newsletter Opt Out') )
{
relLeads.add(currLead);
}
}
return relLeads;
}
catch (System.Nullpointerexception e)
{
System.debug('Record Type Mapping got messed up, returning current list to continue');
return relLeads;
}
}

private void processRelevant(list<Lead> relLeads)
{
// Both String Keys for maps are Email addresses
map<String, Lead> leadMap = new map<String, Lead>();
map<String, list<Contact>> emailContactMap = new map<String, list<Contact>>();
list<Contact> contacts;
list<String> keys = new list<String>();
for ( Lead currLead : relLeads )
{
Lead aLead = new Lead();
aLead = currLead;
leadMap.put(currLead.Email, aLead);
}
contacts = [ SELECT Id, Email, Manufacturer_Update__c, Retailer_Update__c FROM Contact WHERE Email IN :leadMap.keySet() ];
 
for ( Contact c : contacts )
{
if ( emailContactMap.containsKey(c.Email) )
{
emailContactMap.get(c.Email).add(c);
}
else
{
emailContactMap.put(c.Email, new list<Contact>{c});
}
// Collect leads whose Email were not retrieved
keys.add(c.Email);
}
 
list<Contact> contactsToUpdate = new list<Contact>();
 
for ( String s : emailContactMap.keySet() )
{
if ( leadMap.get(s).OptOutType__c.equalsIgnoreCase('ManufacturerUpdate') )
{
for ( Contact c : emailContactMap.get(s) )
{
c.Manufacturer_Update__c = 'no - has unsubscribed';
contactsToUpdate.add(c);
}
}
else if ( leadMap.get(s).OptOutType__c.equalsIgnoreCase('RetailerUpdate') )
{
for ( Contact c : emailContactMap.get(s) )
{
c.Retailer_Update__c = 'no - has unsubscribed';
contactsToUpdate.add(c);
}
}
}
 
// Create Task for unprocessed Leads
list<Lead> unprocessed = new list<Lead>();
list<Task> errorTasks = new list<Task>();
 
for ( String s : keys )
{
leadMap.remove(s);
}
unprocessed = leadMap.values(); 
 
for ( Lead currLead : unprocessed )
{
errorTasks.add(new Task(WhoId = currLead.Id, Subject = 'Unsubscription failed!', OwnerId = owner.Id));
}
 
// This block seems not to be executed at all / correctly from the Web-To-Lead Form
try
{
update contactsToUpdate;
 
if ( errorTasks != NULL && errorTasks.size() != 0 )
{
insert errorTasks;
}
 
// Code Coverage for Exception
if ( Test.isRunningTest() )
{
System.debug('Throwing error intentionally');
insert new Account();
}
  
}
catch(System.DmlException e)
{
System.debug('The process just crashed with error message: ' + e.getMessage());
}
}
}
Best Answer chosen by Roger Wicki
Roger WickiRoger Wicki
Hi Martha

I finally got it working. The key was that Web-To-Lead first inserts a lead without information (so trigger.new on insert is useless) and then updates the very same lead with the information provided. Jeff May from the Community pointed that out here (https://success.salesforce.com/answers?id=90630000000hAp2AAE).

This means I don't need to have the debug log anymore, but thanks for the hint. I didn't try it yet but "Default Lead Creator" can't be the reason as that is me. The reason may however be "Default Lead Owner" which is someone else.

All Answers

Martha_SenetaMartha_Seneta
I know you said "Because the Web To Lead process isn't run by any existing user", so I may be misunderstanding.  But I believe you should be able to setup a debug log like you normally would.  Go to setup and check your Web-to-Lead settings for the "Default Lead Creator"; I think that's the user you want to use for debugging.
Roger WickiRoger Wicki
Hi Martha

I finally got it working. The key was that Web-To-Lead first inserts a lead without information (so trigger.new on insert is useless) and then updates the very same lead with the information provided. Jeff May from the Community pointed that out here (https://success.salesforce.com/answers?id=90630000000hAp2AAE).

This means I don't need to have the debug log anymore, but thanks for the hint. I didn't try it yet but "Default Lead Creator" can't be the reason as that is me. The reason may however be "Default Lead Owner" which is someone else.
This was selected as the best answer