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
mark-azmark-az 

Triggers - Update Task Name (Contact) from Case

Hello.  I'm pretty new to triggers, and am somewhat stuck.  I'm trying to write a trigger that will look at tasks, and if they were created under a case, pull the Case Contact (WhoId) down onto the Task in the 'Name' field.  I have the first piece of logic working which checks to see if the task is related to a case.  When I get to the SOQL query, though, it always returns zero results.  I have tried looking over numerous examples and even hard-coding a case id that should work, but it still comes back empty.  Does anyone have any ideas?  Any assistance would be appreciated, and thanks in advance. Here's the trigger:

 

trigger UpdateCaseTask on Task (before insert, before update)
{

  String tempId;
  String contactId;
  String recType;
  List<Task> newValues = trigger.new;
  List<Id> caseIds = new List<Id>();
  List<Case> caseData = new List<Case>();
  Map<Id,Case> caseMap = new Map<Id,Case>();
  Boolean haveCases = false;

 

// This for look checks the tasks to see if they are tied to a case
for (Task newValue: newValues){
  tempId=newValue.WhatId;
  if(tempId.substring(0,4)=='500R') {
    caseIds.add(tempId);  
    haveCases = true;
    }   
}
// If we have activities that are tied to cases, query for the case information
if (haveCases) { 
       caseData=[Select Id,ContactId,RecordTypeId from Case where Id in: caseIds];
       for (Case c:caseData) {   
           caseMap.put(c.Id,c);
           }  
}    
// Rebuild the list of tasks that need updates   
   for (Task newValue: NewValues) {
       tempId=newValue.WhatId;
       contactId=newValue.WhoId;
 system.debug ('trying to update Task '+caseMap.get(tempId).ContactId);  
 system.debug ('filling in task');  
       if(tempId.substring(0,4)=='500R') {
           contactId=caseMap.get(tempId).ContactId;
       }
      }
}

Best Answer chosen by Admin (Salesforce Developers) 
BritishBoyinDCBritishBoyinDC

In case this helps - this seems to work in my Dev Environment - I noticed that my cases don't start with 500R, but 5003...so this code uses the object prefix function to check for cases - I think that might be the issue...

 

trigger UpdateCaseTask on Task (before insert, before update) {

String caseKeyPrefix = Case.sObjectType.getDescribe().getKeyPrefix();


    Set<Id> caseIds = new Set<Id>();
    
    for (Task t: Trigger.new)     {
     
     if (t.WhatId != null) { 
             String taskWhatId = t.WhatId;
                
                 if (taskWhatId.startsWith(caseKeyPrefix ) ) {
                        caseIds.add(t.WhatId);
                 }
            
            }
            
     } //end first loop
     
     //Now search for Cases
     Map<Id, Id> ConCaseMap = new Map<Id, Id> ();
     
     for (Case c: [Select Id, ContactId from Case where Id in :caseIds]) {
     
             if (c.ContactId != null ) {
             ConCaseMap.put(c.Id, c.ContactId);
             } 
     }

//Now Loop again and update Contact
  for (Task t: Trigger.new)     {
     
     if (t.WhatId != null) { 
              if (ConCaseMap.containsKey(t.WhatId) ) {
              t.WhoId = ConCaseMap.get(t.WhatId);
              }
          }
          
    }
    
    } //end trigger      

 

All Answers

Damien_Damien_

I cleaned up your trigger for you and added a couple of debugs around your query, what do they spit out?

 

trigger UpdateCaseTask on Task (before insert, before update)
{
	Set<Id> caseIds = new Set<Id>();
	for (Task curr: Trigger.new)
	{
		caseIds.add(curr.WhatId);
	}
	
	System.debug('Curr Ids = ' + caseIds);
	//Run this test on a task that looks up to a case and see what is returned
	Map<Id, Case> caseMap = new Map<Id, Case>([SELECT ContactId FROM Case WHERE Id IN: caseIds]);
	System.debug('case map = ' + caseMap);
	
	for (Task currTask: Trigger.new)
	{
		Case tempCase = caseMap.get(currTask.WhatId);
		if (tempCase != null)
		{
			currTask.WhoId = tempCase.ContactId;
		}
	}
}

 

BritishBoyinDCBritishBoyinDC

In case this helps - this seems to work in my Dev Environment - I noticed that my cases don't start with 500R, but 5003...so this code uses the object prefix function to check for cases - I think that might be the issue...

 

trigger UpdateCaseTask on Task (before insert, before update) {

String caseKeyPrefix = Case.sObjectType.getDescribe().getKeyPrefix();


    Set<Id> caseIds = new Set<Id>();
    
    for (Task t: Trigger.new)     {
     
     if (t.WhatId != null) { 
             String taskWhatId = t.WhatId;
                
                 if (taskWhatId.startsWith(caseKeyPrefix ) ) {
                        caseIds.add(t.WhatId);
                 }
            
            }
            
     } //end first loop
     
     //Now search for Cases
     Map<Id, Id> ConCaseMap = new Map<Id, Id> ();
     
     for (Case c: [Select Id, ContactId from Case where Id in :caseIds]) {
     
             if (c.ContactId != null ) {
             ConCaseMap.put(c.Id, c.ContactId);
             } 
     }

//Now Loop again and update Contact
  for (Task t: Trigger.new)     {
     
     if (t.WhatId != null) { 
              if (ConCaseMap.containsKey(t.WhatId) ) {
              t.WhoId = ConCaseMap.get(t.WhatId);
              }
          }
          
    }
    
    } //end trigger      

 

This was selected as the best answer
Damien_Damien_

You don't need to bother checking for the correct prefix at all.  When you run the query with the set of ids, it gets taken of there.

Damien_Damien_

@BritishBoyinDC

 

Instead of adding an extra check in here, you can just add an additional filter to your query:

 

for (Case c: [Select Id, ContactId from Case where Id in :caseIds AND ContactId != null]) {
     
             ConCaseMap.put(c.Id, c.ContactId);
     }
BritishBoyinDCBritishBoyinDC

Good point...

 

I've sometimes had requirements that branch depending on the whatid prefix - so then it can make sense to parse them up front, and process accordingly...  

mark-azmark-az

Hey, thank you both for the quick responses.  Damien, your solution was quite a bit cleaner than where I started.  I went with the second one because I need to check for record type as well, and I can put that into the select pretty easily.  However, I wanted to thank you both for the help and the surprisingly quick responses.  Many thanks.

mark-azmark-az

Spoke too soon - I'm really close on this now, but am stuck on my last point.  I need to add a check for a certain type of case based on record type.  I added this at the top:

 

Id cRtId = [select Id,Name from RecordType where name='IBS Discovery Day Follow-Up' and SOBjectType='Case' limit 1].Id;

 

(Read through the forums a bit and this looked like the right way to reference the record type instead of hardcoding).  I tried adding this to the SELECT query but it doesn't like the format:

 

   for (Case c: [Select Id, ContactId, RecordTypeId from Case
                   where Id in :caseIds AND ContactId!=null AND RecordTypeId=cRtId])

 

Without this check it complies and works ok, but if I add new case record types it will incorrectly update their activities as well.  I have tried looking up SOQL query info and can't quite find anything about this.  Does anyone have any ideas?  Thanks.

Damien_Damien_

You need to add the binding to the variable:

 

 for (Case c: [Select Id, ContactId from Case where Id in :caseIds AND ContactId != null AND RecordTypeId = :cRtId])

 

You don't need to bring back RecordTypeId in the query if you are already handling that portion in the query.

BritishBoyinDCBritishBoyinDC

Try adding a colon since it is a bind variable... 

 

where Id in :caseIds AND ContactId!=null AND RecordTypeId= :cRtId])

mark-azmark-az

Ah, I totally missed that, was going crazy.  That fixed it and I am golden.  Thank you both for the quick responses and all of the help.