0

I am trying to create a Trigger on Contact, which fires if a custom checkbox (Primary_Contact__c) is TRUE.

When the checkbox is TRUE, it should update a custom lookup field (also called Primary_Contact__c) on the related Account.

Additionally, only one contact should be a primary contact (Checkbox = TRUE).

Currently when checking the Primary_Contact__c on contact, nothing happens.

trigger primaryContact on Contact (after insert, after update) {

    Map<Id, Id> accountPrimaryContactMap = new Map<Id, Id>();
    Map<Id, Account> accountsToUpdate = new Map<Id, Account>();
    List<Contact> contactsToUpdate = new List<contact>();

    FOR (Contact con : Trigger.new) {
        if(con.account != NULL){
            accountPrimaryContactMap.put(con.Accountid, con.id);
        }
    }

    FOR (Contact con : [SELECT id,name,Primary_Contact__c FROM Contact WHERE Accountid IN : accountPrimaryContactMap.keySet()]){
        if (trigger.newMap.get(con.Id).Primary_Contact__c && (!trigger.oldMap.get(con.Id).Primary_Contact__c && trigger.oldMap != null)) {
            if(con.Account.Primary_Contact__c != con.id){
                account a = new account(Primary_Contact__c = con.Id);
                accountsToUpdate.put(a.id,a);
            }
        }else{
            con.Primary_Contact__c = FALSE;
            contactsToUpdate.add(con);
        }
    }
    if (!accountsToUpdate.values().isEmpty()) {
        update accountsToUpdate.values();
    }
    if (!contactsToUpdate.isEmpty()) {
        update contactsToUpdate;
    }
}
1
  • 1
    (1) you are going to have recursion issues as when you update the contacts; the trigger will fire again; (2) the tests for empty are unnecessary; DML on empty lists is a NOP
    – cropredy
    Nov 28, 2017 at 1:51

2 Answers 2

1

You should do a few things differently to help layer your application:

//Logic-Less Trigger on Case
Trigger ContactTrigger on Contact (after insert, after update) {

ContactTriggerHandler handler = new ContactTriggerHandler();

if(Trigger.IsAfter && Trigger.IsInsert){
    handler.AfterInsert(Trigger.new, Trigger.newMap);
} else if(Trigger.IsAfter && Trigger.IsUpdate){
    handler.AfterUpdate(Trigger.old, trigger.oldMap, Trigger.new, trigger.newMap);
}

}


//Trigger Handler
public class ContactTriggerHandler{

public static void AfterInsert(List<Contact> newList, Map<Id,Contact> newMap){
    ContactTriggerHelper.HandlePrimaryContactOnAccount(newList);
}

public static void AfterUpdate(List<Contact> oldList, Map<Id,Contact> oldMap, List<Contact> newList, Map<Id,Contact> newMap){
    ContactTriggerHelper.HandlePrimaryContactOnAccount(newList);
}

}


//TriggerHelper - Does real Logic
public class ContactTriggerHelper{

public Static void HandlePrimaryContactOnAccount(List<Contact> contactList){
    Map<Id,Id> accountIDToPrimaryContactID = new Map<Id,Id>();
    for(Contact cont : contactList){
        if(cont.Primary_Contact__c == true && cont.AccountID != null){
            accountIDToPrimaryContactID.put(cont.AccountID, cont.Id);
        }
    }

    if(!accountIDToPrimaryContactID.keyset().IsEmpty()){
        List<Account> accountsWithPrimaryContact = [SELECT ID, Primary_Contact__c (Select ID FROM Contacts WHERE Primary_Contact__c = true) FROM Account WHERE Id in: accountIDToPrimaryContactID.keyset()];
        List<Account> AccountsToUpdate = new List<Account>();
        For(Account acc : accountsWithPrimaryContact){
            if(!Acc.Contacts.IsEmpty() && Acc.Contacts[0].id != accountsWithPrimaryContact.get(acc.id)){
                Throw New MyException (‘You cannot set contact with ID: ’+ accountsWithPrimaryContact.get(acc.id)+’ as the primary contact for Account with ID: ’++Acc.id+’ Because Contact with ID: ’+  Acc.Contacts[0].id+’ is already set as primary’);
            }
        else{
            AccountsToUpdate.add( new Account(Id=acc.id, Primary_Contact__c = accountsWithPrimaryContact.get(acc.id));
        }
    }
    if(!AccountsToUpdate.IsEmpty()){
        Update accountsToUpdate;
    }
}

}

}
5
  • Thanks Mitch! One question, why is the helper its own class? I thought the handler also held the logic? Nov 28, 2017 at 2:08
  • I always like to keep the helper or service layer separate from the trigger handler. Trigger kicks off the process, Handler controls order of execution and recursion prevention, and the service/helper layer just does static actions on records. Nov 28, 2017 at 2:10
  • Also, I didn't test that code or run it at all - it's just an example of how I would solve the problem :) Nov 28, 2017 at 2:12
  • 1
    Also, it's probable better to do this before update and insert. Then you could throw the exception when you find the account already has one and halt the execution much earlier. Nov 28, 2017 at 2:17
  • Hey Mitch, thanks for posting this, however there are dozens of errors on all components. I am struggling to fix up even the syntax, to then test, and understand each components functions. Is there anyway you can tidy your solution up? Ta :) Nov 28, 2017 at 2:48
0

Your line should be as below contactsToUpdate.add(con);

1
  • Thanks Suneel, well spotted. I have updated the post as the trigger isnt performing as desired, even with the typo fixed. Nov 27, 2017 at 23:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .