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
Alaric WimerAlaric Wimer 

Need help with a Mass Update - change all account and contact owners to match the owner of the opportunities they are related to

I need some help with how to approach the following tasks.

1. I need to perform a one time mass update that will change all account and contact owners to match the owner of the opportunities they are related to. 

2. (after the one time mass update is finished) when opp owner is updated also updated related contact and account owner to the new owner

I'm not really sure how to approach these in the most efficient way and safest way. I'm thinking an Apex trigger but would need some guidance with the code. Any help is greatly appreciated. Thank you!

Boss CoffeeBoss Coffee
Are Opportunities related to Account and Contact via a lookup relationship? If so, is there a guarantee that all Opportunities looking up to a Account/Contact have the same owner? Would there be a case where two different Opportunities look up to the same Account but have different Owners?
Alaric WimerAlaric Wimer

Hi thanks for your reply! Here's the answers to your questions.

 

1. From the Opp, Account is lookup. Contact is related through Contact Roles. 2. Is there a guarantee?

 

2. Is there a guarantee? No, and that’s the current problem. This solution will guarantee that when the opp owner is updated, the contact and account owners will also be updated to match the same owner .

 

3. No such case is expected.

Boss CoffeeBoss Coffee
For existing Opportunities, you can execute the following in the Execute Anonymous Window. My org has more than one Opportunity looking up to the same Account, and it would cause issues if the Account (or Contact) is in the same list more than once to be updated. Assuming that all Opportunities that look up to an Account have the same Owner, then the following code should work. It adds the first Account that needs to be updated via Opportunity Owner Id and ignores any other attempts to add that same Account to the list to be updated.
    // Get a map of all existing Opportunities
    Map<Id,Opportunity> oppMap = new Map<Id,Opportunity>([
        SELECT Id, AccountId, OwnerId 
        FROM Opportunity
    ]);
    // Create and populate a list of the Opportunity Ids
    List<Id> oppIds = new List<Id>();
    oppIds.addAll(oppMap.keySet());
    
    // Get a list of Opportunity Contact Roles that look up to the Opportunities we fetched
    List<OpportunityContactRole> ocrList = [
        SELECT Id, ContactId, Opportunity.OwnerId
        FROM OpportunityContactRole 
        WHERE OpportunityId IN :oppIds
    ];
    
    // Create a list for Account Ids and Contact Ids
    List<Id> accIds = new List<Id>();
    List<Id> conIds = new List<Id>();
    
    // Go through each Opportunity we grabbed and add the Account Id to the list
    for(Opportunity opp : oppMap.values()) {
        accIds.add(opp.AccountId);
    }
    
    // Go through each Opportunity Contact Role we grabbed and add the Contact Id to the list
    for(OpportunityContactRole ocr : ocrList) {
        conIds.add(ocr.ContactId);
    }
    
    // Fetch the map of Accounts that Opportunities look up to
    Map<Id,Account> accMap = new Map<Id,Account>([
        SELECT Id, OwnerId
        FROM Account
        WHERE Id IN :accIds
    ]);
    
    // Fetch the map of Contacts that Opportunity Contact Roles look up to
    Map<Id,Contact> conMap = new Map<Id,Contact>([
        SELECT Id, OwnerId
        FROM Contact
        WHERE Id IN :conIds
    ]);
    
    // Create a map for Accounts and Contacts to be updated
    Map<Id,Account> updateAccounts = new Map<Id,Account>();
    Map<Id,Contact> updateContacts = new Map<Id,Contact>();
    // Create a temporary Account and Contact for placeholding in following for loops
    Account tempAcc;
    Contact tempCon;
    
    // For each Opportunity
    for(Opportunity opp : oppMap.values()) {
        // Check if the Account to be updated has already been added to the map
        if(accMap.containsKey(opp.AccountId) && !updateAccounts.containsKey(opp.AccountId)) {
            // Then update the Account Owner Id with the Opportunity Owner Id
            tempAcc = accMap.get(opp.AccountId);
            tempAcc.OwnerId = opp.OwnerId;
            updateAccounts.put(opp.AccountId, tempAcc);
        }
    }
    
    // For each Opportunity Contact Role
    for(OpportunityContactRole ocr : ocrList) {
        // Check if the Contact to be updated has already been added to the map
        if(conMap.containsKey(ocr.ContactId) && !updateContacts.containsKey(ocr.ContactId)) {
            // Then update the Contact Owner Id with the Opportunity Owner Id
            tempCon = conMap.get(ocr.ContactId);
            tempCon.OwnerId = ocr.Opportunity.OwnerId;
            updateContacts.put(ocr.ContactId, tempCon);
        }
    }
    
    // Update the list of Accounts and the list of Contacts
    update updateAccounts.values();
    update updateContacts.values();
Alaric WimerAlaric Wimer

Thank you for the code with comments! That really helps me understand. I will be trying this in a testing environment soon and will let you know. I'm also interested in finding out how to do this for all future records. When opp owner is updated also updated related contact and account owner to the new owner.