This document discusses building a "Pre-Lead Workspace" custom object in Salesforce to keep incomplete lead list data separate from the lead object. It includes:
- Creating a custom object with fields to store pre-lead data
- Using validation rules and process builder to automatically move records to the lead object when complete
- An example user interface and how users would interact with it
The goal is to prevent dirty or incomplete data from entering the lead object directly, while still allowing users to work with pre-lead lists in Salesforce instead of Excel. When enough data is entered, records would automatically convert to leads.
In-Depth Performance Testing Guide for IT Professionals
Move Out of Excel and into a Pre-Lead Workspace by Dan Donin
1. Dan Donin
Business Systems Analyst
Stalk me:
Dan.Donin@Jivesoftware.com
https://www.linkedin.com/in/danieldonin
Building a Pre-Lead Workspace
How to keep incomplete lists out of your lead object and not force people to work out of excel.
2. Forward-Looking Statements
Statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any
of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking
statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or
service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for
future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts
or use of our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our
service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth,
interruptions or delays in our Web hosting, breach of our security measures, the outcome of any litigation, risks associated with completed and any possible
mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our
employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com
products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of
salesforce.com, inc. is included in our annual report on Form 10-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most
recent fiscal quarter. These documents and others containing important disclosures are available on the SEC Filings section of the Investor Information
section of our Web site.
Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not
be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available.
Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
3. Incomplete Lists
• Everyone gets incomplete lead lists
• Loading these into the Lead object is a quick way to dirty data
• Working these lists in excel makes it difficult to track and measure metrics
5. A Pre-Lead Workspace Object
What makes up this
solution
• Custom Object
• Custom Fields
• Validation Rules
• Process Builder
• A small chunk of
Apex (Optional)
7. We Call it “The Island”
• The only relationship
is to the user table
• Keeps dirty data out of
our lead object!
8. The Magic
Let PB do the heavy lifting
• Once enough data is collected it will flow
into the lead object on its own!
9. We want to check when the record is added
or updated
The Process!
We want to check when the record is added
or updated
We use customized logic in this case to make
sure that State is filled when the country is
United States
1 AND 2 AND 3 AND 4 AND 5 AND 6 AND 7
AND (8 OR (9 AND 10))
We just map the fields on the Lead object to
the reference fields from the PLW record!
13. Object Detail
Formula Fields Formula’s
Possible Existing Lead/Contact -
IF(Count__c > 1,
HYPERLINK('https://na35.salesforce.com/_ui/search/ui/UnifiedSe
archResults?searchType=2&sen=001&sen=00Q&sen=01t&sen=
003&sen=a14&sen=005&sen=006&sen=800&sen=701&sen=a2I
&sen=a0z&str='&Email__c,
'Multiple Dupes Found'),
IF( Possible_Dupe__c <> NULL,
HYPERLINK('https://na35.salesforce.com/'&Possible_Dupe__c,'h
ttps://na35.salesforce.com/'&Possible_Dupe__c), NULL))
Record Sync’d –
IF( TEXT(Status__c) = "SFDC Ready", "This Record has already
been sync'd. Please " +
HYPERLINK("/_ui/search/ui/UnifiedSearchResults?searchType=
2&str=" + Email__c, " find the new record") + " in
Salesforce.",IMAGE("/servlet/servlet.FileDownload?file=0154100
00001RFl","Requirements"))
14. trigger DupeIslandCheck on Pre_Lead_Workspace__c (beforeinsert, before update) {
/* Checks email address agaisnt Leads/Contacts for possible Dupes. This only does a simple email check.
* if it finds any matches it dumps the Lead/Contact ID into a field that then displays the salesforce URL on the record*/
//Thanks to Kevin Purdy for helping me on this he is a boss.
List<Pre_Lead_Workspace__c> sdrListLoad = new List<Pre_Lead_Workspace__c>();
// Quick lookup referencefrom email to record
Map<String, Pre_Lead_Workspace__c> sdrMap = new Map<String, Pre_Lead_Workspace__c>();
// Flat set of new emails coming in to check
Set<String> sdrEmails = new Set<String>();
//Now to check for Update vs Insert. On Update only check for Email Change on Insert check for Email Null
If(Trigger.isUpdate){
For(Pre_Lead_Workspace__c sdr : Trigger.New){
//Populate Trigger Old to compare
Pre_Lead_Workspace__c oldSdr = Trigger.oldMap.get(sdr.id);
//If Email is set to Null clear out SDR Count and Possible Dupe without a lookup.
If(oldSdr.Email__c != Null && sdr.Email__c == Null){
sdr.Count__c = 0;
sdr.Possible_Dupe__c = Null;
}
//Now check if Email Changed 4/27 Also added if the recordis older than a day not to fire if the Email is Null
Else If(sdr.Email__c != Null && oldSdr.Email__c != sdr.Email__c || sdr.Email__c != Null && oldSdr.LastModifiedDate < Date.today().addDays(-1)){
sdrMap.put(sdr.Email__c, sdr);
sdrEmails.add(sdr.Email__c);
sdr.Count__c = 0;
sdr.Possible_Dupe__c = Null;
}
}
} Else If(Trigger.isInsert) {
For(Pre_Lead_Workspace__c sdr : Trigger.New){
If(sdr.Email__c != Null) {
sdrMap.put(sdr.Email__c, sdr);
sdrEmails.add(sdr.Email__c);
}
}
}
//Map the matches 4/27 added in != NULL to try and fix a forever index
Map<String, Lead> leadMap = new Map<String, Lead>([SELECTId, Email FROM Lead WHERE Email IN :sdrEmails AND isConverted = FALSE AND Email != NULL]);
Map<String, Contact> contactMap = new Map<String, Contact>([SELECTId, Email FROM Contact WHERE Email IN :sdrEmails AND Email != NULL]);
//Iterate our duplicates and tie them back to the recordsthat triggered them
For(StringmysteryKey : leadMap.keySet()) {
Lead l = leadMap.get(mysteryKey);
Pre_Lead_Workspace__c sdrWithDupe = sdrMap.get(l.email);
// Do something with the duplicate
sdrWithDupe.Possible_Dupe__c = l.id;
if (sdrWithDupe.Count__c == Null) {
sdrWithDupe.Count__c = 0;
}
sdrWithDupe.Count__c++;
}
For(StringmysteryKey : contactMap.keySet()){
Contact c = contactMap.get(mysteryKey);
Pre_Lead_Workspace__c sdrWithDupe = sdrMap.get(c.email);
// Do something with the duplicate
sdrWithDupe.Possible_Dupe__c = c.id;
if (sdrWithDupe.Count__c == Null) {
sdrWithDupe.Count__c = 0;
}
sdrWithDupe.Count__c++;
}
}
@isTest
public class DupeIslandCheckTest {
static testMethod void DupeIslandCheckTest(){
Lead testLead = new Lead(FirstName= 'Testy', LastName= 'McTesterson', Email='FindThisDupe@abc.com',
Company = 'This Will be Found');
Lead testLead2 = new Lead(FirstName = 'Testy', LastName= 'McTesterson2', Email='DontThisDupe@abc.com',
Company = 'This Wont be Found');
Contact testContact = new Contact(FirstName = 'TestyMc' , LastName = 'Testerson', Title = 'TestyMcTesting',
Email = 'FindThisDupe2@abc.com');
Contact testContact2 = new Contact(FirstName = 'TestyMc' , LastName = 'Testerson2', Title = 'TestyMcTesting',
Email = 'DontThisDupe2@abc.com');
insert testLead;
insert testLead2;
insert testContact;
insert testContact2;
Pre_Lead_Workspace__c testSDR = new Pre_Lead_Workspace__c(First_Name__c = 'Lead1', Email__c='FindThisDupe@abc.com', Count__c = NULL);
Pre_Lead_Workspace__c testSDR2 = new Pre_Lead_Workspace__c(First_Name__c = 'Lead2', Email__c='DontFindAnything@abc.com', Count__c = NULL);
Pre_Lead_Workspace__c testSDR3 = new Pre_Lead_Workspace__c(First_Name__c = 'Lead3', Email__c='FindThisDupe2@abc.com', Count__c = NULL);
Pre_Lead_Workspace__c testSDR4 = new Pre_Lead_Workspace__c(First_Name__c = 'Lead4', Email__c='DontFindAnything2@abc.com', Count__c = NULL);
insert testSDR;
insert testSDR2;
insert testSDR3;
insert testSDR4;
testSDR.Email__c = 'DontFindAnything@abc.com';
testSDR2.Email__c = 'FindThisDupe@abc.com';
update testSDR;
update testSDR2;
testSDR.Email__c = NULL;
update testSDR;
}
}
Trigger
Test Class
Editor's Notes
Intro slide
Talk about who I am, short and sweet.
Key Takeaway:We are a publicly traded company. Please make your buying decisions only on the products commercially available from Salesforce.
Talk Track:
Before I begin, just a quick note that when considering future developments, whether by us or with any other solution provider, you should always base your purchasing decisions on what is currently available.
Bullet One - Ask who has these type of lists and the different ways people work them/load them into SFDC (Marketing automation, DataLoader, etc…)
Bullet Two – The ways that these lists can make data quality take a nose dive
Bullet Three – Hard to measure metrics when things are done in excel or outside standard business processes
TELL ME DAN HOW DO I FIX THIS?!
Give a quick run over the object and how it is customizable to YOUR needs!
The UI for end users. Again customizable to YOUR needs!
This is how it fixes dirty data. The data is contained and cant talk to the rest of the system as it is related to NOTHING (other than the user table so records can be owned). This allows it to be the playground of incomplete data that excel lists are without having to worry about messing up Lead metrics, or creating dirty lead records.