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
John Murphy 38John Murphy 38 

Apex trigger to calculate due dates for generated task list

I need to generate a project task list with due dates for each task  The due dates are calcualted b taking the total # of days for the project and dividing by the number of tasks, so for a 90 day project with 3 tasks, each task would be 30 days apart, with teh first occuring 30 days after the project start date.  The follwing code gives me the tasks, but each task has the same due date -Start_date +30 days.  So I have something wrong in the For loop, but cna't figure out what it is.  Can someone help?

trigger tasks on Project__c (after insert)

{List<Task> newTasks = new List<Task>();

for (Project__c proj : Trigger.New) {
    Date DueDate = proj.Start_Date__c+30;
    Date nextDueDate = DueDate;
    
    for (Integer i = 0; i < proj.Number_of_Tasks__c; i++) 
    
    {
        Integer taskDur = integer.valueOf(proj.Task_Duration__c*(i+1));
        nextDueDate = DueDate.addDays(taskDur);

        newTasks.add(new Task(
            Subject ='Project Task - '+ (i+1),  
            Status = 'In progress',
            Priority = 'High',
            ActivityDate =  nextDueDate,
            WhatId = proj.id
        ));
    }

    //proj.Number_Of_Tasks__c = 0;


insert newTasks;

}
}
Best Answer chosen by John Murphy 38
Maharajan CMaharajan C
Hi John,

Please use the below code i have made some more changes:

Integer TaskDuration = proj.Start_Date__c.daysBetween(proj.End_Date__c);   // Check the Field API Names as you have here:


trigger tasks on Project__c (after insert)
{
List<Task> newTasks = new List<Task>();

for (Project__c proj : Trigger.New) {

    Date StartDate = proj.Start_Date__c;
    Integer TaskDuration = proj.Start_Date__c.daysBetween(proj.End_Date__c);   
    
    for (Integer i = 0; i < proj.Number_of_Tasks__c; i++) 
    
    {
        //Integer taskDur = integer.valueOf(proj.Task_Duration__c*(i+1));   // Populate the value for Task_Duration__c field in project i think in your record it have value as 0 it should be 30 or some what . if you are using this line then remove the  Integer TaskDuration.
        Integer taskDur = integer.valueOf(TaskDuration*(i+1));
        Date nextDueDate = StartDate.addDays(taskDur); 

        newTasks.add(new Task(
            Subject ='Project Task - '+ (i+1),  
            Status = 'In progress',
            Priority = 'High',
            ActivityDate =  nextDueDate,
            WhatId = proj.id
        ));
    }
}
if(newTasks.size() > 0 )
insert newTasks;
}


Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!

Thanks,
Raj

All Answers

Maharajan CMaharajan C
Hi John,

Please use the below code but please read the comments in the  code and change as per the comments:

The reason you are having the same due date value is the proj.Task_Duration__c field return the value 0.check that field.

trigger tasks on Project__c (after insert)
{
List<Task> newTasks = new List<Task>();

for (Project__c proj : Trigger.New) {
    //Date DueDate = proj.Start_Date__c+30;    // if you adding the 30 days and below also use Task_Duration__c(value as 30) field then here it will       give the start date as 60 days after project start date 

    Date DueDate = proj.Start_Date__c;
    Integer TaskDuration = 30;   // use like this Integer TaskDuration = proj.Task_Duration__c;
    Date nextDueDate = DueDate;
    
    for (Integer i = 0; i < proj.Number_of_Tasks__c; i++) 
    
    {
        //Integer taskDur = integer.valueOf(proj.Task_Duration__c*(i+1));   // Populate the value for Task_Duration__c field in project i think in your record it have value as 0 it should be 30 or some what . if you are using this line then remove the  Integer TaskDuration.
        Integer taskDur = integer.valueOf(TaskDuration*(i+1));
        nextDueDate = DueDate.addDays(taskDur); 

        newTasks.add(new Task(
            Subject ='Project Task - '+ (i+1),  
            Status = 'In progress',
            Priority = 'High',
            ActivityDate =  nextDueDate,
            WhatId = proj.id
        ));
    }
}
if(newTasks.size() > 0 )
insert newTasks;
}

Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!


Thanks,
Raj
 
mritzimritzi
Please use two different dates on Project (Start Date, End Date) and create validation rules that End Date > start Date.
Use following code to acheive desired result:
Apex Class:
(please change object/field API names to suit your requirements)
public class ProjectTriggerHandler{
    public ProjectTriggerHandler(){
    }
    public void createTasksOnInsert(List<Project__c> projectList){
        if(projectList == null || projectList.size() == 0)
            return;
        List<Task> taskList = new List<Task>();
        //create tasks with different due dates
        for(Project__c project:projectList){
            Integer noOfDays = project.Start_Date__c.daysBetween(project.End_Date__c);
            //you can do have validations for dates, bcoz there can be number of edge cases on this
            //assuming that noOfDays is perfectly divisible by Number_of_Tasks__c
            Integer daysPerTask = noOfDays/project.Number_of_Tasks__c;
            Date taskEndDate = project.Start_Date__c.addDays(daysPerTask);
            for(Integer i=0; i<project.Number_of_Tasks__c; i++){
                Task task = new Task(
                    Subject ='Project Task - '+ (i+1),
                    Status = 'In progress',
                    Priority = 'High',
                    ActivityDate =  taskEndDate,
                    WhatId = proj.id
                );
                taskEndDate = taskEndDate.addDays(daysPerTask);
                taskList.add(task);
            }
        }
        if(taskList.size() > 0)
            insert taskList;
    }
}

Trigger:
trigger ProjectTrigger on Project__c(before Insert, before Update, before Delete,
                                    after Insert, after Update, after Delete, after Undelete){
    if(Trigger.isAfter && Trigger.isInsert){
        new ProjectTriggerHandler().createTasksOnInsert(Trigger.new);
    }
}

If this helps solve your problem, please mark this as BEST ANSWER.
 
John Murphy 38John Murphy 38
Hi Raj,  You code works when the Task duration is always 30 days, but I need it to be the Project duration (End Date- Start Date) divided by Number of Tasks.  The Task_Duration is calcuating correctly, I can see this on the project page itself, since I have the filed visible.  But it does not seem to have value in the trigger, as you state.  This is the problem I can't figure out.
John Murphy 38John Murphy 38
Hi mritzi,  I tried your solution as well, but when I do I get the following error: 
Error: Compile Error: Method does not exist or incorrect signature: void createTasksOnInsert(List<Project__c>) from the type ProjectTriggerHandler at line 6 column 37
Not sure what this means, exactly, that line of code looks good to me.  Any ideas?
mritzimritzi
First save the apex class.
Once done, then create trigger. It will get saved.
Maharajan CMaharajan C
Hi John,

I think the Task duration field you have as the formula field and do you have the start date and end date field then one small change only. If it is yes please use the below change:

Integer TaskDuration = proj.Start_Date__c.daysBetween(proj.End_Date__c);   // Check the Field API Names as you have here:


trigger tasks on Project__c (after insert)
{
List<Task> newTasks = new List<Task>();

for (Project__c proj : Trigger.New) {
    //Date DueDate = proj.Start_Date__c+30;    // if you adding the 30 days and below also use Task_Duration__c(value as 30) field then here it will       give the start date as 60 days after project start date 

    Date DueDate = proj.Start_Date__c;
Integer TaskDuration = proj.Start_Date__c.daysBetween(proj.End_Date__c);   // use like this Integer TaskDuration = proj.Task_Duration__c;
    Date nextDueDate = DueDate;
    
    for (Integer i = 0; i < proj.Number_of_Tasks__c; i++) 
    
    {
        //Integer taskDur = integer.valueOf(proj.Task_Duration__c*(i+1));   // Populate the value for Task_Duration__c field in project i think in your record it have value as 0 it should be 30 or some what . if you are using this line then remove the  Integer TaskDuration.
        Integer taskDur = integer.valueOf(TaskDuration*(i+1));
        nextDueDate = DueDate.addDays(taskDur); 

        newTasks.add(new Task(
            Subject ='Project Task - '+ (i+1),  
            Status = 'In progress',
            Priority = 'High',
            ActivityDate =  nextDueDate,
            WhatId = proj.id
        ));
    }
}
if(newTasks.size() > 0 )
insert newTasks;
}

Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!

Thanks,
Raj
Maharajan CMaharajan C
Hi John,

Please use the below code i have made some more changes:

Integer TaskDuration = proj.Start_Date__c.daysBetween(proj.End_Date__c);   // Check the Field API Names as you have here:


trigger tasks on Project__c (after insert)
{
List<Task> newTasks = new List<Task>();

for (Project__c proj : Trigger.New) {

    Date StartDate = proj.Start_Date__c;
    Integer TaskDuration = proj.Start_Date__c.daysBetween(proj.End_Date__c);   
    
    for (Integer i = 0; i < proj.Number_of_Tasks__c; i++) 
    
    {
        //Integer taskDur = integer.valueOf(proj.Task_Duration__c*(i+1));   // Populate the value for Task_Duration__c field in project i think in your record it have value as 0 it should be 30 or some what . if you are using this line then remove the  Integer TaskDuration.
        Integer taskDur = integer.valueOf(TaskDuration*(i+1));
        Date nextDueDate = StartDate.addDays(taskDur); 

        newTasks.add(new Task(
            Subject ='Project Task - '+ (i+1),  
            Status = 'In progress',
            Priority = 'High',
            ActivityDate =  nextDueDate,
            WhatId = proj.id
        ));
    }
}
if(newTasks.size() > 0 )
insert newTasks;
}


Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!

Thanks,
Raj
This was selected as the best answer
John Murphy 38John Murphy 38
I got it to work with a minor adjustment to get the task duration.  I just did the calc in teh trigger and made it a decimal value to get it to work.  I think my issue before was an order of operations issue, where the field task_duration is not being calcuated until after the task list was created..  Thanks for all the help!

trigger tasks on Project__c (after insert)
{
List<Task> newTasks = new List<Task>();

for (Project__c proj : Trigger.New) {

    Date StartDate = proj.Start_Date__c;
    Decimal TaskDuration = (proj.Start_Date__c.daysBetween(proj.End_Date__c)/(proj.Number_of_Tasks__c));   
    
    for (Integer i = 0; i < proj.Number_of_Tasks__c; i++) 
    
    {
    Integer taskDur = integer.valueOf(TaskDuration*(i+1));
        Date nextDueDate = StartDate.addDays(taskDur); 

        newTasks.add(new Task(
            Subject ='Project Task - '+ (i+1),  
            Status = 'In progress',
            Priority = 'High',
            ActivityDate =  nextDueDate,
            WhatId = proj.id
        ));
    }
}
if(newTasks.size() > 0 )
insert newTasks;
}
John Murphy 38John Murphy 38
One last thing, this is more of an odd thing I'd like to fix than a requirement.  The Task List (activities) area shows the tasks in reverse chronological order.  So, for example, if I have 4 tasks, with teh latest having a due date of Dec 1, that last taks is actually at the top of the list.  I was thiking of a wya to fix this when I generate the list but then I noticed that if I add a new task manually witha  due date of tomorrow, it will put that task at the bottom of the list, becasue it has the nearest due ddate, whch seems backwards to me.   It seems to be only in Lightning, not in Classic.  Is there a setting or something where this can be changed?
naman gupta 33naman gupta 33
Hi All, I am unable to create the following task using Apex triggers.
It should be possible for a user to enter the number of tasks (in the Number of Tasks field). When the project is saved standard Salesforce tasks should be automatically generated (i.e. if the user entered 3 then 3 tasks are created automatically). This can be done by means of an Apex trigger that should work something like as follows:
  • When a new Project is inserted
  • The requested number of tasks are automatically created
  • Ideally, the trigger should calculate due dates for the tasks by working out the number of days between the project start and end dates and distributing the task due dates more or less evenly across this period.