3

I'm trying to create a trigger that updates a field on a contact whenever the contact changes ownership. The trigger saves without error, and my test class for the trigger gives a 100% code coverage result. However, when I test changing ownership on a contact, the field does not change. Here is my trigger:

trigger BusinessDivisionUpdateCont on Contact (before update) 
{
    Set<Id> relatedContactIdSet = new Set<Id>();
    for (Contact cont : Trigger.new)
    {
        if (cont.OwnerId != null)
        {
            relatedContactIdSet.add(cont.OwnerId);
        }
    }
    Map<Id, User> relatedContactsMap = new Map<Id, User>([
            SELECT Id, Default_Business_Division__c
            FROM User WHERE Id IN :relatedContactIdSet
            ]);                                                    
    User ApiUser = [Select Id from User where Name = 'System'];
    for (Contact newCont : Trigger.new)
    {
        Contact oldCont = Trigger.oldMap.get(newCont.Id);
        if (oldCont.ownerId != null)
        {
            if ((oldCont.OwnerId != newCont.OwnerId)
                    && (newCont.Owner != ApiUser)
                    && (oldCont.OwnerId != null)
                    && (newCont.OwnerId != null))
            {
                User newOwner = relatedContactsMap.get(newCont.OwnerId);
                newCont.Business_Division__c = newOwner.Default_Business_Division__c;
            }
        }
    }
}

Does the field not update because the ownership change isn't occurring on the contact level, but rather the account level? In other words, to change a contact's ownership, you have to change the ownership of the account that the contact belongs to. Changing the account automatically changes ownership of the contact to the new account owner. Even though this is the case, the trigger is still looking to see if the contact changed ownership, which it did. So I'm not sure why the field wouldn't update with the new information on the new owner. Any help would be awesome!

  • 2
    as a side note - 'my test class for the trigger gives a 100% code coverage result' suggests that your test class isn't doing the proper asserts to see if the code is functioning - 100% code coverage just means every line executed without an exception being thrown – cropredy May 9 '14 at 20:00
  • 2
    side note 2 - in a before update trigger - every Contact will have an ownerId - all those tests for ownerid != null are not required. The expression 'newCont.Owner != ApiUser' is a bit odd as you are comparing objects - I would do newCont.ownerId != ApiUser.id – cropredy May 9 '14 at 20:03
  • Your trigger looks OK to me. I suggest you interactively check both cases: updating the owner of the Account and updating the owner of the Contact and see if only the latter works. You will also ultimately need a unit test for both so that would be another way to check. A change in one object that is referenced by a formula field in an "other" object does not result in the "other" object trigger firing; this may be another example of change not causing indirect triggers to fire, and require you to also have an Account on trigger that updates the child Accounts. – Keith C May 9 '14 at 20:40
3

Have you considered using a Worfklow Rule or Formula Field to meet this requirement? It looks like you simply want the Business_Division__c field to be in sync with the owners Busines_Division__c field. To do that you could use a Workflow Rule / Field Update to copy Owner.Default_Business_Division__c into Contact.Business_Division__c.

The Formula Field would be on Contact, and its formula would be Owner.Business_Division__c. You could even add the check in the Formula or Field Update to ignore the API User.

Moving this to "Clicks not Code" via Workflow Rule or Formula Field will save you Apex Code, Unit Tests, and Deployment troubles. It is also best practice to use "Clicks" wherever possible.

  • We chose to go with a picklist over a formula as we need to have the ability to manually change the value of the field on the contact page. In other words, there are cases where the values for the contact field and the User field will be different. Is it possible to create a workflow rule to update for all cases of the user's field? Or would we need to make twenty different workflow rules to account for all twenty possible options on the User field? – grimsvotn May 9 '14 at 21:15
  • That makes sense why you couldn't use a FF then. For most fields you could do this with one Workflow Rule EXCEPT picklists. Workflow Field Updates for a Picklist don't allow for formula values either, so you would need to do 20 Workflow Rules, one for each value in your picklist you want to set as you have to set a specific value. – CoryCowgill May 10 '14 at 18:51
  • I'd still play around with Workflow Rules, Formula Fields and your field types and see if you can find a way to avoid doing this in Apex Code. If you get creative you may find a way to solve for this without Apex code. And even with 20 Workflow Rules your technical debt is often less than an Apex Trigger. I can always have my BA / Admin update the Workflow Rules, but I have to get a developer to fix a trigger which is often more expensive. – CoryCowgill May 10 '14 at 18:55
  • Of course, your mileage may vary. ;) – CoryCowgill May 10 '14 at 18:56
0

The reason your field is not being updated is because the IF statement will always be FALSE, for the reason that crop1645 notes in a comment above. newCont.Owner is a null User object, since no related objects are available from trigger.new. I created the following trigger on Contact to verify this.

trigger Contact_Trigger on Contact (before update) 
{

    Contact thisCon = Trigger.new[0];
    User thisUser = [select Id, Name from User where Id = :trigger.new[0].OwnerId];

    for (Integer i = 0; i < Trigger.new.size(); i++)
    {
        if (i == 0)
            if (Trigger.new[i].Owner != thisUser)
                Trigger.new[i].addError('Different: ' + Trigger.new[i].Owner + ' | ' + thisUser);
    }

}

As crop1645 says, you need to compare the newCont.OwnerId with ApiUser.Id instead of newCont.Owner and ApiUser.

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.