On a test class for a class that handles lead conversion via apex, 6 out of 7 methods (the ones that convert the lead) are failing in production. However, I can run the test in a fresh sandbox and it passes.
There are no callouts on the test class or the class that does the lead conversion, and I cannot figure out where the callout is happening. The stack trace on the error is empty:
Methods defined as TestMethod do not support Web service callouts
Stack Trace: null
I do have an invocable method on opportunities that does a callout to set exchange rate. It should not be triggered for the type of opportunity created by the lead conversion, and I tried deactivating the process that fires the callout but still got the error when running the test in production.
Are there any known differences in this behavior between sandbox and production? Any suggestions on how to figure out what callout is being called? I literally refreshed the sandbox today and all test methods pass in sandbox.
I will paste the full test and class in below in case it helps. Thanks.
Test Class
@isTest
private class ConvertLeadControllerTests {
@isTest static void TestConvertLead() {
PageReference ref = Page.ConvertLead;
Test.setCurrentPage(ref);
Lead myLead = GetLead();
insert myLead;
system.debug('mylead id = ' +mylead.Id);
ApexPages.CurrentPage().getParameters().put('id', myLead.Id);
ApexPages.CurrentPage().getParameters().put('status', EncodingUtil.urlEncode('1st Op - Qualified for New Idea Call', 'UTF-8'));
ConvertLeadController cl = new ConvertLeadController();
cl.ConvertLead();
Account acc =[Select Id From Account Where Name=:myLead.Company Limit 1];
system.debug('acc id = ' + acc.id);
Opportunity opp = [Select Id From Opportunity Where AccountId =:acc.Id];
System.assert(acc != null);
System.assert(opp != null);
}
@isTest static void TestConvertLeadWithExistingContactAndAccount() {
PageReference ref = Page.ConvertLead;
Test.setCurrentPage(ref);
Account acc = new Account();
acc.Name = 'TestOrg';
insert acc;
Contact con = new Contact();
con.LastName = 'TestLast';
con.FirstName = 'TestFirst';
con.AccountId = acc.Id;
con.Email = 'test@test.com';
insert con;
Lead myLead = GetLead();
insert myLead;
ApexPages.CurrentPage().getParameters().put('id', myLead.Id);
ApexPages.CurrentPage().getParameters().put('status', EncodingUtil.urlEncode('1st Op - Qualified for New Idea Call', 'UTF-8'));
ConvertLeadController cl = new ConvertLeadController();
cl.ConvertLead();
PageReference pgRef = cl.convertLead2();
Opportunity opp = [Select Id From Opportunity Where AccountId =:acc.Id];
OpportunityContactRole ocr = [Select Id from OpportunityContactRole where ContactId=:con.Id];
system.assert(ocr != null);
System.assert(opp != null);
}
@isTest static void TestConvertLeadWithExistingAccount() {
PageReference ref = Page.ConvertLead;
Test.setCurrentPage(ref);
Account acc = new Account();
acc.Name = 'TestOrg';
insert acc;
Lead myLead = GetLead();
insert myLead;
ApexPages.CurrentPage().getParameters().put('id', myLead.Id);
ApexPages.CurrentPage().getParameters().put('status', EncodingUtil.urlEncode('1st Op - Qualified for New Idea Call', 'UTF-8'));
ConvertLeadController cl = new ConvertLeadController();
cl.ConvertLead();
PageReference pgRef = cl.convertLead2();
Opportunity opp = [Select Id From Opportunity Where AccountId =:acc.Id];
System.assert(opp != null);
}
@isTest static void TestConvertLeadWithExistingContact() {
PageReference ref = Page.ConvertLead;
Test.setCurrentPage(ref);
Account acc = new Account();
acc.Name = 'TestOrg1';
insert acc;
Contact con = new Contact();
con.LastName = 'TestLast';
con.FirstName = 'TestFirst';
con.AccountId = acc.Id;
con.Email = 'convertLeadControllerTests123@convertLeadControllerTests.com';
insert con;
Lead myLead = GetLead();
mylead.Email = 'convertLeadControllerTests123@convertLeadControllerTests.com';
insert myLead;
ApexPages.CurrentPage().getParameters().put('id', myLead.Id);
ApexPages.CurrentPage().getParameters().put('status', EncodingUtil.urlEncode('1st Op - Qualified for New Idea Call', 'UTF-8'));
ConvertLeadController cl = new ConvertLeadController();
cl.ConvertLead();
PageReference pgRef = cl.convertLead2();
OpportunityContactRole ocr = [Select Id from OpportunityContactRole where ContactId=:con.Id];
system.assert(ocr != null);
}
@isTest static void TestConvertLeadEmailMatchWithExistingContact() {
PageReference ref = Page.ConvertLead;
Test.setCurrentPage(ref);
Account acc = new Account();
acc.Name = 'TestOrg1';
insert acc;
Contact con = new Contact();
con.LastName = 'Con TestLast';
con.FirstName = 'Last TestFirst';
con.AccountId = acc.Id;
con.Email = 'convertLeadControllerTests12@convertLeadControllerTests.com';
insert con;
Lead myLead = GetLead();
mylead.Email = 'convertLeadControllerTests12@convertLeadControllerTests.com';
myLead.Nominator__c = con.Id;
myLead.Reference_1__c = con.Id;
myLead.Reference_2__c = con.Id;
myLead.Reference_3__c = con.Id;
insert myLead;
ApexPages.CurrentPage().getParameters().put('id', myLead.Id);
ApexPages.CurrentPage().getParameters().put('status', EncodingUtil.urlEncode('1st Op - Qualified for New Idea Call', 'UTF-8'));
ConvertLeadController cl = new ConvertLeadController();
cl.ConvertLead();
PageReference pgRef = cl.convertLead2();
OpportunityContactRole ocr = [Select Id from OpportunityContactRole where ContactId=:con.Id LIMIT 1];
system.assert(ocr != null);
}
//Assigns the lead to the queue before invoking the conversion logic.
@isTest static void TestConvertLeadFromQueue() {
Group testGroup = new Group(Name='TestGroup', Type='Queue');
insert testGroup;
System.runAs(new User(Id=UserInfo.getUserId()))
{
QueuesObject testQueue = new QueueSObject(QueueID = testGroup.id, SObjectType = 'Lead');
insert testQueue;
}
Lead myLead = GetLead();
myLead.OwnerId = testGroup.Id;
insert myLead;
ApexPages.CurrentPage().getParameters().put('id', myLead.Id);
ApexPages.CurrentPage().getParameters().put('status', EncodingUtil.urlEncode('1st Op - Qualified for New Idea Call', 'UTF-8'));
ConvertLeadController cl = new ConvertLeadController();
cl.ConvertLead();
Account acc =[Select Id From Account Where Name=:myLead.Company Limit 1];
Opportunity opp = [Select Id From Opportunity Where AccountId =:acc.Id];
System.assert(opp != null);
}
@isTest static void TestCancel() {
PageReference ref = Page.ConvertLead;
Test.setCurrentPage(ref);
ApexPages.CurrentPage().getParameters().put('id', 'aaaaaaaaaaaaaaa');
ConvertLeadController cl = new ConvertLeadController();
cl.Cancel();
}
private static Lead GetLead(){
//+need to randomize the data created by this test
//contact and org name also need to match, so need to use testsetup and query for them
//Integer randomInt = Integer.valueOf(math.rint(math.random()*1000000));
Lead myLead = new Lead();
myLead.FirstName = 'TestFirst';
myLead.LastName = 'TestLast';
myLead.Company = 'TestOrg';
myLead.Status = 'Nomination - First Review needed';
myLead.Country_of_Election__c = 'United States';
myLead.Country_Of_Social_Impact__c ='India';
myLead.Diamond_of_Social_Impact__c = 'Asia';
myLead.Cluster__c = 'Aging';
myLead.Country = 'India';
myLead.Organization_Type__c ='Bank';
myLead.Address_Type__c ='Home';
myLead.State ='Karnataka';
myLead.Street ='Bangalore';
myLead.Target_Population__c ='Business';
myLead.Gender__c ='Male';
mylead.New_Idea__c ='New Idea';
myLead.Opportunity_Type__c ='Grant';
myLead.Email ='test@test.com';
myLead.Application_Nomination_Attached__c = true;
//myLead.Application_Nomination_Completed__c = true;
myLead.City ='Bangalore';
myLead.Fellow_Type__c ='Global';
myLead.Industry ='Banking';
mylead.Interview_Completed__c =true;
myLead.Phone ='99999999';
myLead.Reference_Check_Completed__c = true;
myLead.Site_Visit_Completed__c = true;
myLead.Preferred_Language__c ='English';
myLead.Research_Completed__c = true;
myLead.RecordTypeId = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('Venture Nominee').getRecordTypeId();
myLead.Acceptable_Legal_Structure__c = 'Legal Structure 1: Candidates with pure non-profit setups';
myLead.Area_of_Impact__c = 'Rural';
return myLead;
}
}
ConvertLeadController Class
public with sharing class ConvertLeadController {
public Lead mylead {get;set;}
public String status {get;set;}
public List<Account> accs {get;set;}
public List<Contact> cons {get;set;}
public ConvertLeadController() {
cons = new List<contact>();
accs = new List<Account>();
mylead = new Lead();
}
//Handles lead conversion
public PageReference ConvertLead(){
try{
PageReference ref;
string leadId = ApexPages.CurrentPage().getParameters().get('id').trim();
//status = EncodingUtil.urldecode(ApexPages.CurrentPage().getParameters().get('status'), 'UTF-8');
status = '1st Op - Qualified for New Idea Call';
mylead = [Select Owner.Type, Owner.IsActive, Company, FirstName,Name,Nominator__c,Reference_1__c ,Reference_2__c ,Reference_3__c ,LastName, Email, Other_Email__c, Personal_Email__c, Work_Email__c, Industry
From Lead Where Id=:leadId];
//If Lead Owner is Queue and user has update access on the lead then set owner as the logged in user. Else return
if(mylead.Owner.Type == 'Queue' || myLead.Owner.IsActive == false){
if(Lead.SObjectType.getDescribe().isUpdateable()){
mylead.OwnerId = UserInfo.getUserId();
update mylead;
}else{
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Error,'Lead must be owned by a person, not a queue, before it can be converted.'));
return null;
}
}
//Check if the account exists. Last modified account is selected if there are multiple accounts
accs = [Select Id,Name,UserRecordAccess.HasEditAccess From Account Where Name=:myLead.Company And Isdeleted=false order by LastModifiedDate desc Limit 1];
//Check if the contact exists based on lead details. The contact will be selected if
//email on the lead matches any emails on Contact. Last modified contact is selected if there are multiple contacts
cons = [Select Id,Name,FirstName,LastName,email,Account.Name,Owner.Name,Country_of_Residence__c, AccountId,UserRecordAccess.HasEditAccess, Account.UserRecordAccess.HasEditAccess From Contact
Where (Email =:myLead.Email OR Other_Email__c =:myLead.Email OR Personal_Email__c =:myLead.Email OR
Work_Email__c =:myLead.Email)
order by LastModifiedDate desc Limit 1];
//If there is match on Contact
if(cons != null && cons.size() >0){
if(!cons[0].UserRecordAccess.HasEditAccess){
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Error,
'We found a match on email with an existing contact in Salesforce, but you do not have Edit access for this Contact. Please reach out to Salesforce Support to proceed.'));
return null;
}
if(!cons[0].Account.UserRecordAccess.HasEditAccess){
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Error,
'We found a match with on email an existing contact in Salesforce, but you do not have Edit access for the Contact\'s Organization. Please reach out to Salesforce Support to proceed.'));
return null;
}
// if exact match found display the message
if(cons[0].FirstName == myLead.FirstName && cons[0].LastName == myLead.LastName){
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.WARNING,
' We found an exact match with an existing contact in Salesforce, who is part of the organization '+ cons[0].Account.Name +'.<br/> Therefore the organization on the opportunity will be set to '+ cons[0].Account.Name +'.<br/> <ul style="list-style-type: circle;padding-top:10px;"><lh style="font-weight:bold;">Next Steps</lh><li>If '+ cons[0].Account.Name +' is not the correct organization for this candidate, you must manually update the contact and opportunity <u>after converting the lead</u>.</li><li>Click \'Convert Lead\' to proceed.</li>'));
return null;
}// if partial match found display the message
else{
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.WARNING,
' We found a partial match (on email but not name) for ' + myLead.Name + ' with the contact '+ cons[0].Name +'.<br/> <ul style="list-style-type: disc;padding-top:10px;"><lh style="font-weight:bold;">Next Steps</lh><li>Review the contact details provided on this page</li><ul style="list-style-type: circle;"><li>If this is the correct contact, choose \'Convert Lead\' to proceed. <br /><i>Note that the organization on the opportunity will be set to '+ cons[0].Account.Name +'. If this is not the correct organization for this candidate, you must manually update the contact and opportunity after converting the lead.</i> </li> <li> If this is not the correct contact, click \'Cancel and Return to Lead\'. <br /> <i>You must manually edit the email address on the lead or the existing contact so that they no longer match. This allows a new contact to be created when converting the lead.<i></li></ul></ul>'));
return null;
}
}else
{ //If there is match on the account
if(accs != null && accs.size() >0){
if(!accs[0].UserRecordAccess.HasEditAccess){
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Error,' We found a match with an existing Organization, but you do not have Edit access to the Organization. Please reach out to Salesforce Support to proceed.'));
return null;
}
}
ref = convertLead2(); // proceed to convert lead
return ref;
}
}catch(Exception ex){
ApexPages.addMessages(ex);
return null;
}
}
// to convert lead on confirmation
public pageReference convertLead2(){
try{
//Convert Lead
Database.LeadConvert lc = new Database.LeadConvert();
lc.setLeadId(mylead.Id);
lc.setConvertedStatus(status);
lc.setDoNotCreateOpportunity(false);
//Added by Dazeworks to rename the Opportunity Name to Ashoka convention
lc.setOpportunityName(mylead.FirstName + ' ' + mylead.LastName + ' - ' + mylead.Industry);
//If there is match on Contact set the Account on opportunity to the Contacts account
if(cons != null && cons.size() >0 ){
lc.setContactId(cons[0].Id);
lc.setAccountId(cons[0].AccountId);
}//Else if there is match on the account only set the account on opportunity and new contact
else if(accs != null && accs.size() >0){
lc.setAccountId(accs[0].Id);
}
Database.LeadConvertResult lcr = Database.convertLead(lc);
PageReference ref;
if(lcr.isSuccess()){ // If success redirect to newly created opportunity
ref = new PageReference('/' + lcr.getOpportunityId());
}
else // If failure redirect to the lead
{
ref = new PageReference('/' + myLead.Id);
}
ref.SetRedirect(true);
//Added by Dazeworks to create Contact role : migration from deprecated code in case 18902
if (lcr.getContactId() != null) {
modifyContactRole('Candidate', lcr.getContactId(), true,lcr.getOpportunityId());
}
if (mylead.Nominator__c != null) {
addContactRole('Nominator', mylead.Nominator__c, false,lcr.getOpportunityId());
}
if (mylead.Reference_1__c != null) {
addContactRole('Reference', mylead.Reference_1__c , false,lcr.getOpportunityId());
}
if (mylead.Reference_2__c != null) {
addContactRole('Reference', mylead.Reference_2__c , false,lcr.getOpportunityId());
}
if (mylead.Reference_3__c != null) {
addContactRole('Reference', mylead.Reference_3__c , false,lcr.getOpportunityId());
}
//ends here
return ref;
}catch(Exception ex){
ApexPages.addMessages(ex);
return null;
}
}
//Redirects back to the lead detail page.
public PageReference Cancel(){
string leadId = ApexPages.CurrentPage().getParameters().get('id').trim();
PageReference ref = new PageReference('/' + leadId);
ref.SetRedirect(true);
return ref;
}
public void modifyContactRole(String roleName, Id contactId, Boolean isPrimary,Id opportunityId) {
if (roleName != null) {
OpportunityContactRole ocr = [select id, role, contactId, opportunityId, isPrimary from OpportunityContactRole where opportunityId = :opportunityId and contactId = :contactId limit 1];
ocr.ContactId = contactId;
ocr.Role = roleName;
ocr.IsPrimary = isPrimary;
update ocr;
Engagement_Role__c engagementRole = new Engagement_Role__c();
engagementRole.Contact__c = contactId;
engagementRole.Opportunity__c = opportunityId;
engagementRole.Role__c = roleName;
engagementRole.isPrimary__c = isPrimary;
insert engagementRole;
}
}
public void addContactRole(String roleName, Id contactId, Boolean isPrimary,Id opportunityId) {
if (roleName != null) {
OpportunityContactRole ocr = new OpportunityContactRole();
ocr.ContactId = contactId;
ocr.OpportunityId = opportunityId;
ocr.Role = roleName;
ocr.IsPrimary = isPrimary;
insert ocr;
Engagement_Role__c engagementRole = new Engagement_Role__c();
engagementRole.Contact__c = contactId;
engagementRole.Opportunity__c = opportunityId;
engagementRole.Role__c = roleName;
engagementRole.isPrimary__c = isPrimary;
insert engagementRole;
}
}
}