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
Terri HenryTerri Henry 

Feedback on User Object Trigger

Hi All, 

I have created a trigger to prevent the deactivation of a user if they own any Accounts, Contacts or unconverted leads - as this causes issues with the Pardot sync (the Marketing team lead me to believe)

The trigger works as expected, though I'm aware that with containing SOQL queries within the FOR loop I'm breaking best practice - but would there be a performance issue on taking this out of the loop and running them on every update (even when they are not needed)

Constructive criticism welcomed

Thanks
 
//Trigger to prevent deactivation of user if they own any records referenced by Pardot.
//Deactivating a user while they still own these records (accounts, contacts, uncoverted leads) will cause issues with Pardot sync

trigger UserPreventDeactivation on User (before update) {
  
    for(User u : Trigger.new){
        User oldU = Trigger.oldMap.get(u.Id);  
        
        //Check if user has changed from active to inactive
        if(!u.IsActive && oldU.IsActive){
            
            //Query number of Accounts, Contacts and Unconverted Leads in User's Name
        	//SHOULD BE OUTSIDE OF LOOP TO BE BULKIFIED? but don't want to run these queries on every update to user if not needed.
        	//but as have only internal users, not likely to deactivate users in bulk
        	Integer contactCount = [SELECT count()
                                      FROM Contact
                                     WHERE ownerId = :u.id
                                     LIMIT 1]; 
        	Integer accountCount = [SELECT count()
                                      FROM Account
                                     WHERE ownerId = :u.id
                                     LIMIT 1];
        	Integer leadCount = [SELECT count()
                                   FROM Lead
                                  WHERE ownerId = :u.id
                                    AND isConverted = FALSE
                                  LIMIT 1];
            
            //add error to screen alerting user
            if( (contactCount + accountCount + leadCount) > 0){
            	u.addError('This user may own accounts, contacts, or unconverted leads.' +
                          'Ensure that these records are transferred to a different owner ' +
                          'before deactivating this user. This is due to issues it will cause ' +
                          'with the Pardot sync.');    
            }     
        }
    }
}



 
Best Answer chosen by Terri Henry
Ravi Dutt SharmaRavi Dutt Sharma

You dont need to run this on every update. Do the calculation only when user has been deactivated.

 

trigger UserPreventDeactivation on User (before update) {
    Set<Id> userIds = new Set<Id>();
    for(User u : Trigger.new){
        User oldU = Trigger.oldMap.get(u.Id);  
        //Check if user has changed from active to inactive
        if(!u.IsActive && oldU.IsActive){
            userIds.add(u.Id);  
        }
    }
    
    List<Contact> contacts;
    List<Account> accounts;
    List<Lead> leads;
    
    if(userIds.size() > 0 ){
        contacts = [SELECT OwnerId FROM Contact WHERE OwnerId IN: userIds];
        accounts = [SELECT OwnerId FROM Account WHERE OwnerId IN: userIds];
        leads = [SELECT OwnerId FROM Lead WHERE OwnerId IN: userIds AND isConverted = FALSE];
    }
    
    Map<Id, boolean> userHasRecords = new Map<Id, boolean>();
    
    for(Id userId: userIds) {
        userHasRecords.put(userId, false); // default value
        for(Contact con: contacts){
            if(con.OwnerId == userId){
                userHasRecords.put(userId, true);
            }
        }
        for(Account acc: accounts){
            if(acc.OwnerId == userId){
                userHasRecords.put(userId, true);
            }
        }
        for(Lead ld: leads){
            if(ld.OwnerId == userId){
                userHasRecords.put(userId, true);
            }
        }
    }
    
    //add error to screen alerting user
    for (Id userId : userHasRecords.keySet()) {
        if (userHasRecords.get(userId)){
            User usr = new User(Id=userId);
            usr.addError('Add your error here');
        }
    } 
}

All Answers

Ravi Dutt SharmaRavi Dutt Sharma

You dont need to run this on every update. Do the calculation only when user has been deactivated.

 

trigger UserPreventDeactivation on User (before update) {
    Set<Id> userIds = new Set<Id>();
    for(User u : Trigger.new){
        User oldU = Trigger.oldMap.get(u.Id);  
        //Check if user has changed from active to inactive
        if(!u.IsActive && oldU.IsActive){
            userIds.add(u.Id);  
        }
    }
    
    List<Contact> contacts;
    List<Account> accounts;
    List<Lead> leads;
    
    if(userIds.size() > 0 ){
        contacts = [SELECT OwnerId FROM Contact WHERE OwnerId IN: userIds];
        accounts = [SELECT OwnerId FROM Account WHERE OwnerId IN: userIds];
        leads = [SELECT OwnerId FROM Lead WHERE OwnerId IN: userIds AND isConverted = FALSE];
    }
    
    Map<Id, boolean> userHasRecords = new Map<Id, boolean>();
    
    for(Id userId: userIds) {
        userHasRecords.put(userId, false); // default value
        for(Contact con: contacts){
            if(con.OwnerId == userId){
                userHasRecords.put(userId, true);
            }
        }
        for(Account acc: accounts){
            if(acc.OwnerId == userId){
                userHasRecords.put(userId, true);
            }
        }
        for(Lead ld: leads){
            if(ld.OwnerId == userId){
                userHasRecords.put(userId, true);
            }
        }
    }
    
    //add error to screen alerting user
    for (Id userId : userHasRecords.keySet()) {
        if (userHasRecords.get(userId)){
            User usr = new User(Id=userId);
            usr.addError('Add your error here');
        }
    } 
}
This was selected as the best answer
Terri HenryTerri Henry
Thanks Ravi