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
aKallNVaKallNV 

Can't call a future Method from a Future Method

Hi all,

I am trying to create a trigger on the User object that will create a corresponding Contact record and update that Corresponding record when the user record is updated. This has been quite a learning process for me, and I thought I was nearly there when I decided that I should also try to sync the User.Manager field with the Contact.ReportsToId field.

 

My solution for this was to create a field on the User object to store its corresponding Contact's id, which would allow me to pull the ContactID right from the User record that was chosen to be the Manager and then fed into into the ReportsToId field on the Contact. The challenge is that because this is a User trigger I have annotate the methods with @future. I was hoping that I could update the Users from the same method that Inserted the new Contacts. In other words, when a user is created my trigger would create a new Contact then after that Contact is created the same class would update the User.ContactID__c field with the newly created ContactId. This results in the following error 'System.AsyncException: Future method cannot be called from a future method.'

 

I then turned to the documentation to find it explicitly stated that this was not possible, and it also stated that it was not possible for an anottated method call a trigger that calls an anottated method. So I guess that rules out creating a second trigger on the Contact object that would update the User object after insert.  At this point, I feel like I'm in a conundrum and would appreciate any suggestions.

 

Thanks,

 

 

public with sharing class userHandler {
	
	//this is the method that is triggered by a User Insert, After Insert
	@future
	public static void createCons(Set<ID> newUs) {
		
		List<User> theNewUs = [select ID, FirstName, LastName,MobilePhone, Email, Department__c, Unit__c, DateofHire__c, TerminationDate__c, Title, Phone from User where ID IN: newUs];
		List<Contact> newCons = new List<Contact>();
		List<User> userUpdate = new List<User>();
		
		for(User newU : theNewUs) {
			Contact theCon = new Contact();
			theCon.FirstName = newU.FirstName;
			theCon.LastName = newU.LastName;
			theCon.Email = newU.Email;
			theCon.Department =newU.Department__c;
			theCon.Unit__c = newU.Unit__c;
			theCon.StartDate__c = newU.DateofHire__c;
			theCon.EndDate__c = newU.TerminationDate__c;
			theCon.Title = newU.Title;
			theCon.Phone = newU.Phone;
			TheCon.MobilePhone = newU.MobilePhone;
			theCon.AccountId = '001Q000000G7LHh';
			theCon.UserId__c = newU.Id;
			theCon.ReportsToId = newU.Manager.Contact__c;			
			newCons.add(theCon);			
		}		
		
		insert newCons;
		
/*After the new cons are inserted in the line above the following code 
updates the User record's ContactID__c field with the newly created ContactID
It is the update statement that throws the no Future method from future method error
because the User Update triggers the next method below called updateCons.*/
												List<Contact> aiCons = [select ID, UserId__c from Contact where UserId__c IN :NewUs];
		
		for(User newUUpdate : theNewUs) {
			for(Contact aiCon : aicons) {
				if(null != aiCon.UserId__c) {
					if(aiCon.UserId__c == newUUpdate.Id) {
						newUUpdate.ContactID__c = aiCon.Id;
						userUpdate.add(newUUpdate);
					}
				}
			}
		}
		
		update userUpdate;
		
	}
	
	@future
	public static void updateCons(Set<ID> existingUs) {
		
		List<Contact> consUpdate = new List<Contact>();
		Map<String,User> idToUser = new Map<String,User>([select ID, FirstName, LastName, Email, Manager.ContactID__c, Department__c, Unit__c, DateofHire__c, TerminationDate__c, Title, Phone, MobilePhone from User where ID IN: existingUs]);
				
		for(Contact existingCon : [select ID, FirstName, LastName, Email, ReportsToId, Department, Unit__c, StartDate__c, EndDate__c, Title, Phone, MobilePhone, UserID__c from Contact where userID__c IN :idToUser.keySet()]) {
			if(existingCon.FirstName != idToUser.get(existingCon.UserID__c).FirstName) {
				existingCon.FirstName = idToUser.get(existingCon.UserID__c).FirstName;
			}
			if(existingCon.LastName != idToUser.get(existingCon.UserID__c).LastName) {
				existingCon.LastName = idToUser.get(existingCon.UserID__c).LastName;
			}
			if(existingCon.Email != idToUser.get(existingCon.UserID__c).Email) {
				existingCon.Email = idToUser.get(existingCon.UserID__c).Email;
			}
			if(existingCon.Department != idToUser.get(existingCon.UserID__c).Department__c) {
				existingCon.Department = idToUser.get(existingCon.UserID__c).Department__c;
			}
			if(existingCon.Unit__c != idToUser.get(existingCon.UserID__c).Unit__c) {
				existingCon.Unit__c = idToUser.get(existingCon.UserID__c).Unit__c;
			}
			if(existingCon.StartDate__c != idToUser.get(existingCon.UserID__c).DateofHire__c) {
				existingCon.StartDate__c = idToUser.get(existingCon.UserID__c).DateofHire__c;
			}
			if(existingCon.EndDate__c != idToUser.get(existingCon.UserID__c).TerminationDate__c) {
				existingCon.EndDate__c = idToUser.get(existingCon.UserID__c).TerminationDate__c;
			}
			if(existingCon.Title != idToUser.get(existingCon.UserID__c).Title) {
				existingCon.Title = idToUser.get(existingCon.UserID__c).Title;				
			}
			if(existingCon.MobilePhone != idToUser.get(existingCon.UserID__c).MobilePhone) {
				existingCon.MobilePhone = idToUser.get(existingCon.UserID__c).MobilePhone;				
			}
			if(existingCon.phone != idToUser.get(existingCon.UserID__c).phone) {
				existingCon.phone = idToUser.get(existingCon.UserID__c).phone;
			}
			//system.assert(false, 'haha '+existingCon.ReportsToId + ' ' + idToUser.get(existingCon.UserID__c).Manager.ContactID__c);
			if(null != existingCon.ReportsToId && (existingCon.ReportsToId != idToUser.get(existingCon.UserID__c).Manager.ContactID__c)) {
				existingCon.ReportsToId = idToUser.get(existingCon.UserID__c).Manager.ContactID__c;
			}
			
			consUpdate.add(existingCon);
		}
		
		update consUpdate;
		
	}
}

 

 

 

 

 

 

 

joshbirkjoshbirk

Yeah, it a paradox of context.  Or, out of context.  Not sure...

 

You might look at either using workflows, or scheduled apex, to modify records after the fact.  It's not real time, but can keep sanity on the records.

aKallNVaKallNV

Sorry, don't know what you mean by 'workflows'...are you talking about workflow rules?

 

Scheduled Apex looks like it might be my last hope, but before I try it does anybody know if it is possible to call a schduled class from something that has been triggered by a future method?

 

I ask because I just had a go at coding a trigger on the contact record to update the corresponding User record, but the user Update is annotated and so is the method that creates the contact. Therefore I'm told again that you can't call a future method from a future method...I was pretty sure it would, but I had to give it a shot. So before I write a scheduled class, I'm curious if anybody knows if this will work.