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
Rebecca Hendricks 9Rebecca Hendricks 9 

Trigger Conflict with Process

Hello,

I'm not getting my code to work out, and believe it is the result of a conflict between the Trigger I've created and a Process builder that was created.  However, for the life of me, I can't figure out where the error in my logic is happening.

Background:
My boss would like to know how many times our Reps have a 30 minute lag between creating/editing tasks.  There are two ways that a task can be created/edited: 1) directly creating/editing a new task from the contact and/or opportunity, and 2) Automatically from a process that is launched when a new contact is created.

As the task can be created as the first actions of the day, as well as not really having a good way of knowing how this task relates to others in the system, I've created some custom fields that will hold a flag on whether it was the first activity of the day (which will always have more than a 30 minutes gap since the last activity action) and whether it was created within 30 minutes of the last task action.  It is these fields that my trigger will update.

Trigger code:
trigger UpdateActivityFlags on Task (before insert, before update) {
    
    Boolean within30Mins = Boolean.valueOf('true');	//assume task was created more than 30 mins since last activity modification
    String userID = UserInfo.getUserId();	//Get User Id for task owner
    DateTime rightNow = system.now();	//get the date/time of when the task is being created
    Date rightNowDate = date.newInstance(rightNow.year(), rightNow.month(), rightNow.day());	//date part only of date/time task is being created
    Task mostRecentTask;
    Date mostRecentTaskDate;
    
    //Need to get most recent activity information
    try{
        mostRecentTask = [SELECT id, LastModifiedDate, LastModifiedTime__c, EditedWithin30MinsOfLastTask__c, Subject
                          FROM Task 
                          Where OwnerId = :userID AND LastModifiedTime__c < :rightNow 
                          ORDER BY LastModifiedTime__c Desc 
                          Limit 1];
        mostRecentTaskDate = Date.newInstance(mostRecentTask.LastModifiedDate.year(), mostRecentTask.LastModifiedDate.month()
                                              , mostRecentTask.LastModifiedDate.day());	//get date portion of most recent activity modification
    } catch(Exception e){
        System.debug('There were no previous tasks for this user. Error information: Type - ' + e.getTypeName() + ' ;  Message - ' + e.getMessage());
    }
    
    //Check if task was created within 30 mins of last activity modification
    //if(mostRecentTask != NULL){	//There IS a previous task to compare myself to
    //    if((rightNow.getTime() - mostRecentTask.LastModifiedTime__c.getTime()) < 1800000 // 30 mins = 1.8E6 milliseconds
    //        || mostRecentTask.Subject.containsAny('- 2 Week Followup') || mostRecentTask.Subject.containsAny('- 2 Month Followup')
    //      ){	
    //        within30Mins = True;
    //    }
    //}
    
    if(mostRecentTask != NULL){	//There IS a previous task to compare myself to
        if(Trigger.isInsert){
            if((rightNow.getTime() - mostRecentTask.LastModifiedTime__c.getTime()) >= 1800000
               && !mostRecentTask.Subject.containsAny('- 2 Week Followup') && !mostRecentTask.Subject.containsAny('- 2 Month Followup')
              ){	
                  within30Mins = false;
              }
        }
        else{
            if((rightNow.getTime() - mostRecentTask.LastModifiedTime__c.getTime()) >= 1800000){
                within30Mins = false;
            }
        }
        
    }
    
    //update flag information
    for (Task t : Trigger.New){
        t.EditedWithin30MinsOfLastTask__c = within30Mins;
        if(mostRecentTask == NULL){	//no previous tasks owned by user
            t.FirstActivityofDay__c = True;	//no other activities means that this is the first one they are creating
        } else {
            if((Date.valueOf(rightNowDate).daysBetween(mostRecentTaskDate)) != 0){	//task creating and last activity modification are not on the same day
                t.FirstActivityOfDay__c = True;
            }
            t.PreviousTaskDateTime__c = mostRecentTask.LastModifiedTime__c;
        }
    }
}
the commented out code is when I set the initial value of the Boolean to false.  However, this really didn't work for the automatic notifications items, so I tried to approach it from the reverse.

Process information for 2 day "automatic" task:
User-added image

Process for 2 week task creation:
User-added image

Process for 2 Month task creation:
User-added image

Questions-Information:
As I stated, as the trigger is on before insert and before update, I think the Process is creating the task, and that is activating the trigger.  However, I thought my trigger had taken into account this information with the check for the subject information.  (I should mention that the words searched for are exactly what is "coded" in the process, and will be the only time this exact phrase is used.)  Even though I've got the information placed into the process, I believe the trigger would over-write it, but thought the subject inclusion would have caught the over-writing and still given it the value it needed, but that's not the case, as my "within 30 minutes" field is not populating with a True value as it should be for these.

Should I be having my trigger execute on After Insert and After Update information, and then update the information on that task again?
 
Waqar Hussain SFWaqar Hussain SF
It seems the trigger is running in recursion. You will have to avoid recursion in the trigger, so it should run only once if the task is created or updated. 

Please see below aritcle to avoid recursion.
https://help.salesforce.com/articleView?id=000133752&language=en_US&type=1


If the problem persist, you can test by deactivating one by one the process builder and trigger. 
Briana L.Briana L.
Please refer to the order of execution for Triggers here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm

As a result of the order of execution, process builder does not fire triggers.

In process builder there is an Action "Apex".
You need to create an apex class with your trigger logic in it, and it must have the @InvocableMethod annotation.
In the Process builder Apex Action, you should select this class and pass your object ids into it.

My suggestion is that you create a single helper class to meet your business needs, then call this helper class from both the trigger context AND the Process builder Apex Action.

Trigger code:
trigger UpdateActivityFlags on Task (before insert, before update) {
    
    UpdateActivityFlagsHelper helper = new UpdateActivityFlagsHelper(); //instantiate the trigger helper
    if(trigger.isBefore && ( trigger.isinsert || trigger.isupdate)){
        System.debug('Passing to before insert or update handler');
        helper.onBeforeInsertorUpdate(trigger.new, trigger.isInsert, false);
    }

}

Then in your trigger helper, have a method called "onBeforeInsertOrUpdate" that takes a list of tasks to represent Trigger.New and a boolean for isInsert or not. You must have another method that is @Invocable in order to handle the context of the helper being called from the process. You can declare the 

Trigger/Process Helper code:
public class UpdateActivityFlagsHelper{

@InvocableMethod
public static void ProcessBuilderContext(List<Task> taskList){
//Call the method that executes the update actions, but pass the variable for "isInsert" directly, and declare that it is coming from Process Builder
         onBeforeInsertOrUpdate(taskList, true, true);
}

public void onBeforeInsertOrUpdate(List<Task> newList, Boolean isInsert, Boolean isProcess){
        Boolean within30Mins = Boolean.valueOf('true');	//assume task was created more than 30 mins since last activity modification
        String userID = UserInfo.getUserId();	//Get User Id for task owner
        DateTime rightNow = system.now();	//get the date/time of when the task is being created
        Date rightNowDate = date.newInstance(rightNow.year(), rightNow.month(), rightNow.day());	//date part only of date/time task is being created
        Task mostRecentTask;
        Date mostRecentTaskDate;
        
        //Need to get most recent activity information
        try{
            mostRecentTask = [SELECT id, LastModifiedDate, LastModifiedTime__c, EditedWithin30MinsOfLastTask__c, Subject
                              FROM Task 
                              Where OwnerId = :userID AND LastModifiedTime__c < :rightNow 
                              ORDER BY LastModifiedTime__c Desc 
                              Limit 1];
            mostRecentTaskDate = Date.newInstance(mostRecentTask.LastModifiedDate.year(), mostRecentTask.LastModifiedDate.month()
                                                  , mostRecentTask.LastModifiedDate.day());	//get date portion of most recent activity modification
        } catch(Exception e){
            System.debug('There were no previous tasks for this user. Error information: Type - ' + e.getTypeName() + ' ;  Message - ' + e.getMessage());
        }
        
        if(mostRecentTask != NULL){	//There IS a previous task to compare myself to
            if(isInsert){
                if((rightNow.getTime() - mostRecentTask.LastModifiedTime__c.getTime()) >= 1800000
                   && !mostRecentTask.Subject.containsAny('- 2 Week Followup') && !mostRecentTask.Subject.containsAny('- 2 Month Followup')
                  ){	
                      within30Mins = false;
                  }
            }
            else{
                if((rightNow.getTime() - mostRecentTask.LastModifiedTime__c.getTime()) >= 1800000){
                    within30Mins = false;
                }
            }
            
        }
        
        List<Task> tasksToUpdate = new List<Task>();
        //update flag information
        for (Task t : newList){
            t.EditedWithin30MinsOfLastTask__c = within30Mins;
            if(mostRecentTask == NULL){	//no previous tasks owned by user
                t.FirstActivityofDay__c = True;	//no other activities means that this is the first one they are creating
            } else {
                if((Date.valueOf(rightNowDate).daysBetween(mostRecentTaskDate)) != 0){	//task creating and last activity modification are not on the same day
                    t.FirstActivityOfDay__c = True;
                }
                t.PreviousTaskDateTime__c = mostRecentTask.LastModifiedTime__c;
            }
        }
if(isProcess){
Database.SaveResult[] srList = Database.update(tasksToUpdate, false);
}else{ upsert tasksToUpdate;}
    }
}

 
Rebecca Hendricks 9Rebecca Hendricks 9
Thanks for the advice.  I located the error.  It was actually the result of an error in the logic on testing the subject line.  I altered this test to be && (!(t.Subject.contains('- 2 Week Followup') || t.Subject.contains('- 2 Month Followup'))).  Besides the logic not being correct I was also using the Subject.containsAny() function, which was matching any of the words with the tasks.  As the automatic tasks have very similar subject strings (only a single word difference) it was causing it to trip when it shouldn't be.