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
tgk1tgk1 

Apex trigger on Task

Hi everyone-

 

I believe I'm coming pretty close to finalizing my apex code.  Unfortunately I'm getting a compile error and could use some help.  I have included comments within the code to show exactly what I'm trying to accomplish.  Can somebody please take a look and see what modifications need to be made?

 

trigger LastSWDate on Task (before insert, before update) {
	
	//To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
	//the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();


//For every task, add it's related to account ID to the set
	for (Task t: Trigger.new){
	  acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
	  Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
	If (t.accountID =!null && t.subject.indexOf('sw') && t.Status == 'Completed')
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
  	  If (acctMap.get.(t.accountID).Last_SW_Activity__c < t.endDateTime || acctMap.get(t.accountID).Last_SW_Activity ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
  		  acctrec.Last_SW_Activity__c = t.endDatetime;
  	}
  }
}

 

 

 

 The error I'm getting states "Invalid field endDatetime for SObject Task".  It's refering to the last line of code.  Does anybody have any idea why it's giving me that error?

Best Answer chosen by Admin (Salesforce Developers) 
Jake GmerekJake Gmerek

 t.accountID =!null in your code should be

 

t.accountID!=null

 

you had the ! and the = switched.

All Answers

My OwnMy Own

 

Can you please verify in the Task schema, Task is not having field "endDatetime", is this custom field your reffering in your object ? , If not filed name should be change. I guess it may be "LastModifiedDate".

 

what do you mean by Task end date???

 

 

FYI, 

Select t.SystemModstamp, t.Status, t.LastModifiedDate, t.ActivityDate From Task t

Jake GmerekJake Gmerek

The task object, as far as I can tell, does not have a field called endDatetime.  An Event has endDatetime, but not an activity.  See below for more information on the available fields for a task.

 

http://www.salesforce.com/us/developer/docs/api/index_Left.htm#CSHID=sforce_api_objects_event.htm|StartTopic=Content%2Fsforce_api_objects_event.htm|SkinName=webhelp

Jake GmerekJake Gmerek

Oops! Sorry about the double post!

tgk1tgk1

Thanks for the help guys.  I did modify the code from an event trigger, so that makes sense that endDateTime isn't being referenced on the task object.  Here's the code I have now, and I'm getting an error message: "Initial term of field expression must be a concrete Sobject: Map <ID, Account>

 

trigger LastSWDate on Task (before insert, before update) {
	
	
	//To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
	//the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();


//For every task, add it's related to account ID to the set
	for (Task t: Trigger.new){
	  acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
	  Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
	If (t.accountID =!null && t.subject.indexOf('sw') && t.Status == 'Completed')
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
  	  If (acctMap.get.(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
  		  acctrec.Last_SW_Activity__c = t.LastModifiedDate;
  	}
  }
}

 I'm essentially trying to do the following:

 

I have a field on the account object called "Last SW Activity", and it's a date field.

I want the apex trigger to look at the tasks associated with an account record, and pull the date of the last completed task - and put it into the "Last SW Activity" field.

Jake GmerekJake Gmerek

Is that error on the same line or a different one?

tgk1tgk1

Sorry- the error is on this line:

 

 If (acctMap.get.(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity ==null){

frederic baudaxfrederic baudax

without looking to much in details on your code i noticed a typpo

 

acctMap.get.(t.accountID).Last_SW_Activity__c

 

should be: acctMap.get(t.accountID).Last_SW_Activity__c

 

further more you should be able to use activitydatetime on task which is the "due date" of the task if i remeber right



Jake GmerekJake Gmerek

 If (acctMap.get.(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity ==null){

 

Has one too many .'s

 

This:

acctMap.get.(t.accountID).Last_SW_Activity__c < t.LastModifiedDate 

Should be:

acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate 

 

I made the extra dot big so I could be sure you saw the difference as it took me a minute to find it.

My OwnMy Own

try like this.

 

 If ((acctMap.get.(t.accountID)).Last_SW_Activity__c < t.LastModifiedDate || (acctMap.get(t.accountID)).Last_SW_Activity ==null){

 

If  this is not, then DateTime.valueOf((acctMap.get.(t.accountID)).Last_SW_Activity__c)  < DateTime.valueOf(t.LastModifiedDate)  do like this.

tgk1tgk1

So close yet so far- I made the modification to the last line, now I'm getting a compile error on this line:

 

 If (t.accountID =!null && t.subject.indexOf('sw') && t.Status == 'Completed')

 

The error is "The AND operator can only be used with boolean expressions".  Since the condition of the if statement is boolean why would it be giving me this error?

Jake GmerekJake Gmerek

 t.subject.indexOf('sw') does not appear to be a boolean expression. You need something like  t.subject.indexOf('sw') == aValue because indexOf returns an integer

My OwnMy Own

 

try with this now. 

 If ((t.accountID =!null) && (t.subject.indexOf('sw')) && (t.Status == 'Completed'))

 

tgk1tgk1

Really appreciate everyones effort on this.  Seems to be the never ending saga with this:

 

trigger LastSWDate on Task (before insert, before update) {
	
	
	//To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
	//the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();


//For every task, add it's related to account ID to the set
	for (Task t: Trigger.new){
	  acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
	  Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
	If ((t.accountID =!null) && (t.subject.indexOf('sw')) && (t.Status == 'Completed'))
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
  	  If (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
  		  acctrec.Last_SW_Activity__c = t.LastModifiedDate;
  	}
  }
}

 My own I tried that out but it's still giving me errors on the line that you wrote stating that the AND and NOT operators can only be used for boolean expressions.

Jake GmerekJake Gmerek

See my reply above.  This (t.subject.indexOf('sw')) is still not a boolean expression.  It returns an integer not a TRUE or FALSE.  I am not sure what you are trying to check with it, but I am guessing that 'sw' appears in the same place in every subject that you want, so you would need (t.subject.indexOf('sw')) == 4 or whatever number that place would be.

tgk1tgk1

Oh okay I see what you're referring to.  How could I change that statement so it would be - task subject starts with 'sw'

My OwnMy Own

If ((t.accountID =!null) && (t.subject.indexOf('sw')>0) && (t.Status == 'Completed'))

Jake GmerekJake Gmerek

(t.subject.indexOf('sw') == 0)

 

That should do the trick because the first index is always 0

Jake GmerekJake Gmerek

My Own

 

(t.subject.indexOf('sw') > 0) would give you tasks that contain 'sw' but not at the begining.

tgk1tgk1

So close....

 

Jake I updated it with your code, but now it's giving me a similar error for the =! operator for the account ID.  Is there a way to convert it to an integer and state that if it's greater > 0 ?  Or do you think there's a better way?

Jake GmerekJake Gmerek

Its telling you that (t.accountID != NULL) is not a boolean expression?

tgk1tgk1

Exactly - that's the same error it's giving me

Jake GmerekJake Gmerek

If you take that block out of your code temporarily, will it compile, cause that should work.

tgk1tgk1

I took that chunk of code out and it did compile.  Unfortunately it's not working - it's not updating the Last SW Activity date field on the account object.

Jake GmerekJake Gmerek


OK two things:

 

1. I just compiled this and it did work, are you sure that it is t.accountID =!null that is giving you the error.

 

integer i = 1;   

task t = new task ();   

if (t.accountID != NULL && i==1){i = 0;}

 

because at some point you will have to add that check back in so that you don't get an exception on acctMap.get(t.accountID).Last_SW_Activity__c as a matter of fact you should perform that check on the line following 

 for( task t:trigger.new){  because anytime that the task is not associated with an account you can ignore the rest of the code.

 

2.  You never update the account object, the last line before the end of the trigger should be:

 

update acctRec;

 

Also I think that the lastmodifieddate field will not be populated/update till after the trigger fires and the record is committed 

so you may have to change the trigger to an (after update, after insert) trigger.

Jake GmerekJake Gmerek

 t.accountID =!null in your code should be

 

t.accountID!=null

 

you had the ! and the = switched.

This was selected as the best answer
tgk1tgk1

You are the man!  Thanks so much to everyone for their help.

 

Here is the working code for inquiring minds:

 

trigger LastSWDate on Task (after insert, after update) {
	
	
	//To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
	//the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();


//For every task, add it's related to account ID to the set
	for (Task t: Trigger.new){
	  acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
	  Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
	If ((t.accountID != null) &&(t.subject.indexOf('sw')==0) && (t.Status == 'Completed'))
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
  	  If (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
  		  acctrec.Last_SW_Activity__c = t.LastModifiedDate;
  		  update acctRec;
  	}
  }
}

 

 

Jake can you let me know where I should add the additional code so it doesn't throw exceptions?  Also I'm not 100% sure how I can do the test class for this one so the code is covered.  I don't want to ask too much of you though, you've been a huge help.

Jake GmerekJake Gmerek

OK, I've cleaned up the code a bit, I will explain below.  This is just the for loop and right after:

 

for (Task t: Trigger.new){
	if (t.accountID != NULL){
	  acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
	  Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity    
	If (((t.subject.indexOf('sw')==0) && (t.Status == 'Completed')) && (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null)){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
  		  acctrec.Last_SW_Activity__c = t.LastModifiedDate;
  	}
      }
  }
  update acctRec;

 I have made three main changes:

1.  You had 2 if statements one after the other and I combined them into one.  You can leave it the way you had it and it should work, but this looks a little cleaner and can be easier to read.

2.  I moved this check: if(t.accountID != NULL), to the top of the for loop.  Essentially, if there is no associated account we are just ignoring the rest of the code in that iteration of the loop.

3.  I moved update acctRec outside of the for loop.  When you call Update (or insert, or delete for that matter) on a collection, in this case a map, it will update all the records in that collection.  So you were updating every account each iteration.  This will let you run into governor limits with bulk processing.  So now, you will be just changing all the records in your for loop and then updating them all once, at the same time.

 

As for the test, here is the logic it should follow:

 

1. Create and insert an account

2. Create and insert a task associating it with the account.

3. Query the Account from the database, this should give you the updated value in Last_SW_Activity__c

4. Do the same for the task

5. Use system.assertEquals or similar to check and see if the task that you queryed has the same value in lastmodifieddate as the account does in Last_SW_Activity__c.

 

That will give you the test coverage that you need, but to be through you should check two more cases with similar logic:

1.  Insert 200 tasks instead of one - will check for bulk inserts/updates

2.  Insert a task that is not associated with an account and make sure an exception is not thrown.

Although these tests are not necessary to get the code working, they may serve you well later by ensuring that your code can not be broken by a later update.

 

Victor QuironVictor Quiron
It seems like there are a few issues in your Apex trigger code. Let's address them one by one:

1. The error message "Invalid field endDatetime for SObject Task" is occurring because you have a typo in the variable name. It should be `t.endDateTime` (with a capital 'D'), not `t.endDatetime`. So, update the last line like this:

```apex
acctRec.Last_SW_Activity__c = t.endDateTime;
```

2. The if statement for checking if the subject of the task contains 'sw' has an issue. You should use the `contains()` method to check if the subject contains 'sw'. Also, you need to make sure it's a completed task before proceeding. Update this part as follows:

```apex
if (t.AccountId != null && t.Subject != null && t.Subject.toLowerCase().contains('sw') && t.Status == 'Completed') {
```

3. The creation of `acctMap` and `acctRec` should be moved outside of the loop for efficiency. You can create the map and get the account records before the loop. I am also facing this problem in my Jobs in pakistan today (http://www.pakistanjobslatest.pk) wordpress site

Here's an updated version of your code:

```apex
trigger LastSWDate on Task (before insert, before update) {
    // Create a set of related account IDs
    Set<ID> acctIDs = new Set<ID>();

    // For every task, add its related account ID to the set
    for (Task t : Trigger.new) {
        acctIDs.add(t.AccountId);
    }

    // Create a map to match the task related to IDs with their corresponding account IDs
    Map<ID, Account> acctMap = new Map<ID, Account>([SELECT ID, Last_SW_Activity__c FROM Account WHERE ID IN :acctIDs]);

    for (Task t : Trigger.new) {
        if (t.AccountId != null && t.Subject != null && t.Subject.toLowerCase().contains('sw') && t.Status == 'Completed') {
            // Get the account record from the map
            Account acctRec = acctMap.get(t.AccountId);
            
            // Check if the Last_SW_Activity__c field is current compared with the latest completed activity
            if (acctRec.Last_SW_Activity__c < t.endDateTime || acctRec.Last_SW_Activity__c == null) {
                // Update the Last_SW_Activity__c field on the account object with the task's end date
                acctRec.Last_SW_Activity__c = t.endDateTime;
            }
        }
    }
}
```

Make sure to use the corrected variable names, check for null values, and use the `toLowerCase()` method to make the 'sw' check case-insensitive. This code should help you avoid the compile error and correctly update the Last_SW_Activity__c field on the account object.