Salesforce Admin Blog

Salesforce Apex Trigger to Reassign Contacts and Open Opportunities

Standard Salesforce functionality allows for the reassignment of Contacts and open Opportunities when the Account to which these records are associated is reassigned to a new User. Clicking the "[change]" link next to the Account Owner field on the Account detail page will allow you to step through a process by which you select a new Account owner and save the changes. Once the changes are made the system will go out and reassign all Contacts and all open Opportunities owned by the old Account Owner to the new Account Owner. This is useful and so automatic that you may not even be aware that it happens.

So what if you work for an organization where Account reassignment tasks are handled in mass or they are handled by some Salesforce integration? Unless the admin performing the mass updates is explicitly updating the related records or there is code in the integration explicitly reassigning the records, the related Contacts and Opportunities are remaining assigned to the old Account Owner.

That's why I wrote the following trigger. It will perform the ownership update for related Contacts and Opportunities when the Owner of the associated Account is updated.

/*
	Created by: Greg Hacic
	Last Update: 28 January 2010 by Greg Hacic
	Questions?: greg@interactiveties.com
*/
trigger reassignRelatedContactsAndOpportunities on Account (after update) {
	try {
		Set<Id> accountIds = new Set<Id>(); //set for holding the Ids of all Accounts that have been assigned to new Owners
		Map<Id, String> oldOwnerIds = new Map<Id, String>(); //map for holding the old account ownerId
		Map<Id, String> newOwnerIds = new Map<Id, String>(); //map for holding the new account ownerId
		Contact[] contactUpdates = new Contact[0]; //Contact sObject to hold OwnerId updates
		Opportunity[] opportunityUpdates = new Opportunity[0]; //Opportunity sObject to hold OwnerId updates
		
		for (Account a : Trigger.new) { //for all records
			if (a.OwnerId != Trigger.oldMap.get(a.Id).OwnerId) {
				oldOwnerIds.put(a.Id, Trigger.oldMap.get(a.Id).OwnerId); //put the old OwnerId value in a map
				newOwnerIds.put(a.Id, a.OwnerId); //put the new OwnerId value in a map
				accountIds.add(a.Id); //add the Account Id to the set
			}
		}
		
		if (!accountIds.isEmpty()) { //if the accountIds Set is not empty
			for (Account act : [SELECT Id, (SELECT Id, OwnerId FROM Contacts), (SELECT Id, OwnerId FROM Opportunities WHERE IsClosed = False) FROM Account WHERE Id in :accountIds]) { //SOQL to get Contacts and Opportunities for updated Accounts
				String newOwnerId = newOwnerIds.get(act.Id); //get the new OwnerId value for the account
				String oldOwnerId = oldOwnerIds.get(act.Id); //get the old OwnerId value for the account
				for (Contact c : act.Contacts) { //for all contacts
					if (c.OwnerId == oldOwnerId) { //if the contact is assigned to the old account Owner
						Contact updatedContact = new Contact(Id = c.Id, OwnerId = newOwnerId); //create a new Contact sObject
						contactUpdates.add(updatedContact); //add the contact to our List of updates
					}
				}
				for (Opportunity o : act.Opportunities) { //for all opportunities
					if (o.OwnerId == oldOwnerId) { //if the opportunity is assigned to the old account Owner
						Opportunity updatedOpportunity = new Opportunity(Id = o.Id, OwnerId = newOwnerId); //create a new Opportunity sObject
						opportunityUpdates.add(updatedOpportunity); //add the opportunity to our List of updates
					}
				}
			}
			update contactUpdates; //update the Contacts
			update opportunityUpdates; //update the Opportunities
		}
	} catch(Exception e) { //catch errors
		System.Debug('reassignRelatedContactsAndOpportunities failure: '+e.getMessage()); //write error to the debug log
	}
}

The code itself is fairly straightforward. If your Users/Admins elect to perform one-off Account ownership changes via the Salesforce GUI then the regular functionality still applies. This code simply keeps you covered when performing Account assignment changes in another manner.
-greg

Share this Post