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
DahveedDahveed 

Design pattern help

My users want to run a report which shows whether or not an Account have contacts which have any of  5 particular contact Titles.  My idea was to create checkboxes of each title on the Account and have a workflow run on the contact which updates these fields on Account when a title contains one of the key titles. However Salesforce cofirmed that I cannot run cross object field updates from a contact to an Account. I can only do this on a custom object with a master detail. I now am doing this via trigger.

I first grab the AccountId from the contact being edited  and put them into a set.

public class contactTitleHandler{
     private Set<Id> AccountIds = new Set<Id>();
     private Map<Id,Account> AccountMap = new Map<Id,Account>();
     private List<Account> AccountsToUpdate = new List<Account>();
     private boolean treasurer;
     private boolean assistantTreasurer;
     private boolean cashManager;
     private boolean CIO;
     private boolean CFO;
     private Id acctId;

 

     public void onBeforeUpdate(List<Contact> updatedRecords){
         for(Contact c: updatedRecords){
             AccountIds.add(c.Account.Id);   
         }
         calculateTitles();
     }

 

// The idea hear was to  grab every contact attached to the Account and check if it contains a key title.

// the problem is I want to set the values on the account only after I've iterated through all the contacts for that one account

// I would then set the values and add it to a list for update

 

     public void calculateTitles(){
         for(Contact c: [SELECT Title, Account.Id FROM Contact WHERE Account.Id IN: AccountIds ORDER BY Account.Id]){
 

// I was thinking some kind of while loop where it checks contacts until the AccountId changes.  Once it does then set the values on

// the account and add it to a list for update

         
             if(c.Title.contains('Treasurer')){
                 treasurer = true;
             }Else If(c.Title.contains('Assistant Treasurer')){
                 assistantTreasurer = true;                 
             }Else If(c.Title.contains('Cash Manager')){
                 cashManager = true;
             }Else If(c.Title.contains('CIO')){
                 CIO = true;
             }Else If(c.Title.contains('CFO')){
                 CFO = true;
             }

         }

 

My question is how would I write something where it iterates until the Account Id changes in the SOQL query?

 

Thanks for any help!!

 

Dahveed

Best Answer chosen by Admin (Salesforce Developers) 
DahveedDahveed

For anyone looking to do something similar this is what I wound up doing. I changed my way of thinking a bit and decided to simulate rollup summaries. I created formula fields for the contact Title which put a one or zero based on whether the Title contains the value I want. I then do a basic rollup for each wanted title value onto the Account. This allows for bulk processing and an accurate count display of contacts with desired titles.

 

Trigger

trigger contactTitleTrigger on Contact (after insert,after update,after delete) {
    
    ContactTitleHandler handler = new  ContactTitleHandler();
    
        
    if(Trigger.isInsert && Trigger.isAfter){
        handler.onAfterInsert(Trigger.New);
    }
        
    if(Trigger.isUpdate && Trigger.isAfter){                                
        handler.onAfterUpdate(Trigger.New);                      
    }
        
    if(Trigger.isDelete && Trigger.isAfter){                                
        handler.onAfterUpdate(Trigger.Old);                      
    }
}
public class contactTitleHandler{
     private Set<Id> AccountIds = new Set<Id>();
     private Map<Id,Decimal> AcctTreasMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctAssistTreasMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctCManagerMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctCIOMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctCFOMap = new Map<Id,Decimal>();
     private List<Account> AccountsToUpdate = new List<Account>();
     
     public void onAfterInsert(List<Contact> newRecords){
         
         for(Contact c: newRecords){
             AccountIds.add(c.AccountId);                               
         }
         
         calculateTitles();
     }
     
     public void onAfterUpdate(List<Contact> updatedRecords){
         for(Contact c: updatedRecords){
             AccountIds.add(c.AccountId);   
         }
         
         calculateTitles();
     }
     
     public void onAfterDelete(List<Contact> deletedRecords){
         for(Contact c: deletedRecords){
             AccountIds.add(c.AccountId);
         }
         calculateTitles(); 
     }
     
     public void calculateTitles(){
         for(AggregateResult ar: [SELECT AccountId, sum(calcTreasurer__c)treas, sum(calcAssistantTreasurer__c)assisttreas, sum(calcCashManager__c)cmanager, sum(calcCIO__c)cio, sum(calcCFO__c)cfo FROM Contact WHERE AccountId IN: AccountIds GROUP BY AccountId]){
             AcctTreasMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('treas'));
             AcctAssistTreasMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('assisttreas'));
             AcctCManagerMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('cmanager'));
             AcctCIOMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('cio'));
             AcctCFOMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('cfo'));
         }
         for(Account a: [SELECT Id,countTreasurer__c,countAssistTreasurer__c FROM Account WHERE Id IN : AccountIds]){
             Decimal treasurer = AcctTreasMap.get(a.Id);
             Decimal assistTreasurer = AcctAssistTreasMap.get(a.Id);
             Decimal cmanager = AcctCManagerMap.get(a.Id);
             Decimal CIO = AcctCIOMap.get(a.Id);
             Decimal CFO = AcctCFOMap.get(a.Id);
             a.countTreasurer__c = treasurer;
             a.countAssistTreasurer__c = assistTreasurer;
             a.countCashManager__c = cmanager;
             a.countCIO__c = CIO;
             a.countCFO__c = CFO;
             AccountsToUpdate.add(a); 
         }
         
         update AccountsToUpdate;
             
         
         
     }    
} 

 

All Answers

Atul111Atul111

Hi,

 

You have to write the trigger on update on Contact. You can use trigger.old and trigger.new. From these list you can check the account id is changed or not, if account id is changed then you can write your logic.

 

Kinldy let me know if you have any other query.

 

Thanks

 

DahveedDahveed

Thanks for the reply. I have the trigger I just put the handler Class on here because that's where my logic is. The trigger executes and passes the Trigger.New and Trigger.old. I follow Mike Leach's example when writing triggers http://www.embracingthecloud.com/2010/07/08/ASimpleTriggerTemplateForSalesforce.aspx

 

I'm not trying to check if the account Id has changed on the contact. I'm trying to write this to handle bulk processing for passing multiple contacts at a time. The contacts activating the trigger may or may not all belong to the same Account.  This is why I first loop through the updatedRecords list(Trigger.New) and create a set of Account id's.  I then want to take each unique account Id and scroll through every contact checking their title and then setting fields on the Account. This is very similar to what a rollup summary would do on an Account but I'm setting 5 checkboxes on the account instead of summing something. Therefore everytime a contact is created, deleted, or updated, the attached account has to be recalculated by scrolling through every contact.

Atul111Atul111
If you want we can discuss about this issue
DahveedDahveed

For anyone looking to do something similar this is what I wound up doing. I changed my way of thinking a bit and decided to simulate rollup summaries. I created formula fields for the contact Title which put a one or zero based on whether the Title contains the value I want. I then do a basic rollup for each wanted title value onto the Account. This allows for bulk processing and an accurate count display of contacts with desired titles.

 

Trigger

trigger contactTitleTrigger on Contact (after insert,after update,after delete) {
    
    ContactTitleHandler handler = new  ContactTitleHandler();
    
        
    if(Trigger.isInsert && Trigger.isAfter){
        handler.onAfterInsert(Trigger.New);
    }
        
    if(Trigger.isUpdate && Trigger.isAfter){                                
        handler.onAfterUpdate(Trigger.New);                      
    }
        
    if(Trigger.isDelete && Trigger.isAfter){                                
        handler.onAfterUpdate(Trigger.Old);                      
    }
}
public class contactTitleHandler{
     private Set<Id> AccountIds = new Set<Id>();
     private Map<Id,Decimal> AcctTreasMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctAssistTreasMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctCManagerMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctCIOMap = new Map<Id,Decimal>();
     private Map<Id,Decimal> AcctCFOMap = new Map<Id,Decimal>();
     private List<Account> AccountsToUpdate = new List<Account>();
     
     public void onAfterInsert(List<Contact> newRecords){
         
         for(Contact c: newRecords){
             AccountIds.add(c.AccountId);                               
         }
         
         calculateTitles();
     }
     
     public void onAfterUpdate(List<Contact> updatedRecords){
         for(Contact c: updatedRecords){
             AccountIds.add(c.AccountId);   
         }
         
         calculateTitles();
     }
     
     public void onAfterDelete(List<Contact> deletedRecords){
         for(Contact c: deletedRecords){
             AccountIds.add(c.AccountId);
         }
         calculateTitles(); 
     }
     
     public void calculateTitles(){
         for(AggregateResult ar: [SELECT AccountId, sum(calcTreasurer__c)treas, sum(calcAssistantTreasurer__c)assisttreas, sum(calcCashManager__c)cmanager, sum(calcCIO__c)cio, sum(calcCFO__c)cfo FROM Contact WHERE AccountId IN: AccountIds GROUP BY AccountId]){
             AcctTreasMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('treas'));
             AcctAssistTreasMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('assisttreas'));
             AcctCManagerMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('cmanager'));
             AcctCIOMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('cio'));
             AcctCFOMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('cfo'));
         }
         for(Account a: [SELECT Id,countTreasurer__c,countAssistTreasurer__c FROM Account WHERE Id IN : AccountIds]){
             Decimal treasurer = AcctTreasMap.get(a.Id);
             Decimal assistTreasurer = AcctAssistTreasMap.get(a.Id);
             Decimal cmanager = AcctCManagerMap.get(a.Id);
             Decimal CIO = AcctCIOMap.get(a.Id);
             Decimal CFO = AcctCFOMap.get(a.Id);
             a.countTreasurer__c = treasurer;
             a.countAssistTreasurer__c = assistTreasurer;
             a.countCashManager__c = cmanager;
             a.countCIO__c = CIO;
             a.countCFO__c = CFO;
             AccountsToUpdate.add(a); 
         }
         
         update AccountsToUpdate;
             
         
         
     }    
} 

 

This was selected as the best answer