0

Situation:

I've been given a task to "Change all child Contacts' Owners to the Account Owner from the parent Account, whenever the Account Owner changes."

I've written the Trigger and Trigger Handler but when it comes to the test class, I am assigning the Account and Contact to one user and then updating it to another user but the Contact doesn't seem to update with the Account Owner even though it works fine through the UI.

Would appreciate any help here on what I'm missing?

Thank You

Code:

Account Trigger:

trigger AccountTrigger on Account (after update) {

    if(Trigger.isAfter){
        if(Trigger.isUpdate){
            // ? Account Owner Changes
            List<Account> lAccountOwnerChanged = New List<Account>();
            for(Account newAccount: Trigger.New){
                Account oldAccount = Trigger.OldMap.get(newAccount.Id);
                if(newAccount.OwnerId != oldAccount.OwnerId){
                    lAccountOwnerChanged.add(newAccount);
                }
            }

            if(lAccountOwnerChanged.size()>0){
                AccountTriggerHandler.updateContactOwners(lAccountOwnerChanged);
            }

    }

}
}

Account Trigger Handler:

public without sharing class AccountTriggerHandler {

    /*****************************************
     *      Update Contact Owners
     *      ---------------------
     * 
     *      @desc   -   Changes all child Contacts' Owner(s) to the Account Owner from the parent Account, whenever the Account Owner changes.
     */
    public static void updateContactOwners(List<Account> lAccountOwnerChanged) {

        Map<Id, Id> mAccountIdandAccountOwnerId = new Map<Id, Id>();
        Map<Id, List<Contact>> mAccountIdandRelatedContacts = new Map<Id, List<Contact>>();

        // ? Is Metadata Setting On
        if(Account_Setting__mdt.getInstance('Default_Settings').Update_Contact_Owners__c == TRUE){
            // Fill in Maps Above
            for(Account a: lAccountOwnerChanged){
                mAccountIdandAccountOwnerId.put((ID)a.Id, (ID)a.OwnerId);
                mAccountIdandRelatedContacts.put((ID)a.Id, a.Contacts);
            }
            // Update Contact Owners
            List<Contact> lContacts2Update = new List<Contact>();
            for(Id i: mAccountIdandAccountOwnerId.keySet()){
                for(Contact c: mAccountIdandRelatedContacts.get(i)){
                    Contact cUpdate = new Contact(
                        Id = c.Id,
                        OwnerId = mAccountIdandAccountOwnerId.get(i)
                    );
                    lContacts2Update.add(cUpdate);
                }
            }
            if(lContacts2Update.size()>0){
                update lContacts2Update;
            }     
        }

    }
}

Account Trigger Handler Test Class

@isTest

public with sharing class AccountTriggerHandlerTest {
 
    @isTest public static void singleAccountOwnerChange() {
        // Data Setup
        
        User user1 = TestDataFactory.createUser1();
        insert user1;

        User user2 = TestDataFactory.createUser2();
        insert user2;

        Account a = new Account(
            Name = 'Test 1',
            OwnerId = user1.Id
        );
        insert a;

        Contact c = new Contact(
            AccountId = a.Id,
            LastName = 'Test Last Name',
            OwnerId = user1.Id
        );

        insert c;

        Account aOwnerUpdate = [
            SELECT Id, Name, OwnerId,
            (SELECT Id, OwnerId FROM Contacts)
            FROM Account
            WHERE Id = :a.Id
        ];

        // Initialize Test
        Test.startTest();

        aOwnerUpdate.OwnerId = user2.Id;      
        update aOwnerUpdate;
       
        Test.stopTest();

        // Retrieve Data

        Contact cRetrieved = [
            SELECT Id, OwnerId
            FROM Contact
            WHERE AccountId = :aOwnerUpdate.Id
        ];

        Account aRetrieved = [
            SELECT Id, OwnerId
            FROM Account
            WHERE Id = :aOwnerUpdate.Id
        ];

        System.debug('This is the Account Owner Id:::::::::::'+aRetrieved.OwnerId);
        System.debug('This is the Contact Owner Id::::::::::::'+cRetrieved.OwnerId);

        // Assert

        System.assertEquals(user2.Id, cRetrieved.OwnerId);

    }
}

Test DataFactory

@isTest
public without sharing class TestDataFactory {

    public static User createUser1() {

        Profile p = [
            SELECT Id
            FROM Profile
            WHERE Name = 'System Administrator'
        ];

        User usr1 = new User(
            Alias = 'admin1', 
            Email='adminuser@testorg.com', 
            EmailEncodingKey='UTF-8', 
            LastName='Testing', 
            LanguageLocaleKey='en_US', 
            LocaleSidKey='en_US', 
            ProfileId = p.Id, 
            TimeZoneSidKey='America/Los_Angeles', 
            UserName='someUniqueUserName'
        );

        return usr1;
    }
    public static User createUser2() {

        Profile p = [
            SELECT Id
            FROM Profile
            WHERE Name = 'System Administrator'
        ];

        User usr1 = new User(
            Alias = 'admin2', 
            Email='adminuser@testorg.com', 
            EmailEncodingKey='UTF-8', 
            LastName='Testing', 
            LanguageLocaleKey='en_US', 
            LocaleSidKey='en_US', 
            ProfileId = p.Id, 
            TimeZoneSidKey='America/Los_Angeles', 
            UserName='someUniqueUserName'
        );

        return usr1;
    }
}
2
  • as an aside if(Account_Setting__mdt.getInstance('Default_Settings').Update_Contact_Owners__c == TRUE){ means that in test context, you are relying on the org's current value for the MDT. The test will break as soon as the org value is false (which could be months or years in the future). Custom MDT should be mocked, just like custom settings for true test isolation
    – cropredy
    Jul 16 at 22:19
  • @cropedy Thank you for pointing that out.
    – Tom G
    Jul 16 at 22:54
4

I wonder why you would want to write a trigger to achieve this functionality. If Account owner is changed, the owner of associated contacts is automatically changed.

Please refer below article for more details: https://help.salesforce.com/articleView?id=sf.account_owner_transfer.htm&type=5

RECORD TRANSFERRED ITEMS
Account Contacts related to the account are transferred to the new owner automatically.

If you still wish to write the trigger and get your test class passed, you will have to pass the account id's whose owner has changed and query the related contacts in the trigger.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.