Task Cost Calculation (Resource Based)

What is the best process for recalculating a Task Cost value?

I have sample project with two tasks, each associated with a Resource. If I programmatically change the Task durations, the cost is not being recalculated as I would have expected. It appears that the Cost and other resource related fields on the task are only updated if the Project is in CalculationMode = Auto at the time the change is made to the task.

We are working with large projects and for performance reasons, we are making changes to the project while it’s in Manual calculation mode.

    Project OriginalProject = new Project(@"C:\SingleTask.mpp") {
    };

    var collector = new ChildTasksCollector();
    TaskUtils.Apply(OriginalProject.RootTask, collector, 0);

    OriginalProject.CalculationMode = CalculationMode.Manual;

    foreach (var tsk in collector.Tasks) {
        if (tsk.Get(Tsk.Uid) == 6) {
            tsk.Set(Tsk.Duration, OriginalProject.GetDuration(10, tsk.Get(Tsk.DurationFormat)));
        }
    }

Is there anyway to get these fields to recalculate without needing to be CalculationMode Auto at the time the change is made?

SingleTask.zip (27.0 KB)

@leglandpalisade

We are investigating this on our end and we will share the feedback with you as soon as the investigation will be completed.

@leglandpalisade

I have created an issue with ID TASKSNET-10282 in our issue tracking system as investigation to evaluate the requirements. This thread has been linked with the issue so that you may be notified once the issue will be addressed.

@leglandpalisade

We have investigated the issue on our end. Actually, there is no specific API for recalculation of the cost-related fields. There are two possible solutions that you can adopt.

Solution1:
In the described scenario the you can adjust task’s duration, correspondent assignment’s work (it’s needed to properly calculate task’s cost) and call project.Calculate() method:

        Project OriginalProject = new Project(@"SingleTask.mpp");

        var collector = new ChildTasksCollector();
        TaskUtils.Apply(OriginalProject.RootTask, collector, 0);

        OriginalProject.CalculationMode = CalculationMode.Manual;

        foreach (var tsk in collector.Tasks)
        {
            if (tsk.Get(Tsk.Uid) == 6)
            {
                tsk.Set(Tsk.Duration, OriginalProject.GetDuration(10, tsk.Get(Tsk.DurationFormat)));
                tsk.Assignments[0].Set(Asn.Work, OriginalProject.GetDuration(10, tsk.Get(Tsk.DurationFormat)));
            }
        }

        OriginalProject.Recalculate();

        var task6 = OriginalProject.RootTask.Children.GetByUid(6);
        Console.WriteLine("Task cost after recalculation: " + task6.Get(Tsk.Cost));

Solution2:

If project.Recalculate() cannot be used due to performance reasons and use case is simple
(there are no overallocation works, fixed costs, etc), you can calculate task’s cost manually:

        Project OriginalProject = new Project(@"SingleTask.mpp");

        var collector = new ChildTasksCollector();
        TaskUtils.Apply(OriginalProject.RootTask, collector, 0);

        OriginalProject.CalculationMode = CalculationMode.Manual;

        foreach (var tsk in collector.Tasks)
        {
            if (tsk.Get(Tsk.Uid) == 6)
            {
                var duration = OriginalProject.GetDuration(10, tsk.Get(Tsk.DurationFormat));
                tsk.Set(Tsk.Duration, duration);
                tsk.Assignments[0].Set(Asn.Work, duration);

                decimal taskCost = 0m;

                foreach (var ra in tsk.Assignments)
                {
                    var resource = ra.Get(Asn.Resource);
                    var assignmentCost = (decimal)ra.Get(Asn.Work).TimeSpan.TotalHours * resource.Get(Rsc.StandardRate);
                    ra.Set(Asn.Cost, assignmentCost);
                    taskCost += ((decimal)ra.Get(Asn.Work).TimeSpan.TotalHours * resource.Get(Rsc.StandardRate));
                }

                tsk.Set(Tsk.Cost, taskCost);
            }
        }

        var task6 = OriginalProject.RootTask.Children.GetByUid(6);
        Console.WriteLine("Task cost after modification: " + task6.Get(Tsk.Cost));

@mudassir.fayyaz Thank you for the suggestions. In the end we decided to adopt a version of Solution 2, calculating the cost manually.

Thank you