refactor(project-finance): streamline task cost calculations and prevent double counting
- Removed fixed cost from budget calculations, as actual costs are now aggregated from logs and backend data. - Updated recursive functions in the FinanceTable and project finance slice to ensure accurate totals without double counting. - Enhanced comments for clarity on the calculation logic for parent and leaf tasks, improving maintainability.
This commit is contained in:
@@ -23,9 +23,9 @@ const secondsToHours = (seconds: number) => seconds / 3600;
|
||||
const calculateTaskCosts = (task: IProjectFinanceTask) => {
|
||||
const hours = secondsToHours(task.estimated_seconds || 0);
|
||||
const timeLoggedHours = secondsToHours(task.total_time_logged_seconds || 0);
|
||||
const fixedCost = task.fixed_cost || 0;
|
||||
|
||||
const totalBudget = (task.estimated_cost || 0) + fixedCost;
|
||||
const totalBudget = task.estimated_cost || 0;
|
||||
// task.total_actual already includes actual_cost_from_logs + fixed_cost from backend
|
||||
const totalActual = task.total_actual || 0;
|
||||
const variance = totalActual - totalBudget;
|
||||
|
||||
@@ -114,8 +114,8 @@ const recalculateTaskHierarchy = (tasks: IProjectFinanceTask[]): IProjectFinance
|
||||
total_actual: totalActual,
|
||||
estimated_seconds: subtaskTotals.estimated_seconds,
|
||||
total_time_logged_seconds: subtaskTotals.total_time_logged_seconds,
|
||||
total_budget: totalEstimatedCost + totalFixedCost,
|
||||
variance: totalActual - (totalEstimatedCost + totalFixedCost)
|
||||
total_budget: totalEstimatedCost,
|
||||
variance: totalActual - totalEstimatedCost
|
||||
};
|
||||
|
||||
return updatedTask;
|
||||
|
||||
@@ -67,29 +67,31 @@ const FinanceTableWrapper: React.FC<FinanceTableWrapperProps> = ({ activeTablesL
|
||||
// Recursive function to calculate totals from task hierarchy without double counting
|
||||
const calculateTaskTotalsRecursively = (tasks: IProjectFinanceTask[]): any => {
|
||||
return tasks.reduce((acc, task) => {
|
||||
// For parent tasks with subtasks, only count the aggregated values (no double counting)
|
||||
// For leaf tasks, count their individual values
|
||||
// For parent tasks with subtasks, aggregate values from subtasks only
|
||||
// For leaf tasks, use their individual values
|
||||
if (task.sub_tasks && task.sub_tasks.length > 0) {
|
||||
// Parent task - use its aggregated values which already include subtask totals
|
||||
// Parent task - only use aggregated values from subtasks (no parent's own values)
|
||||
const subtaskTotals = calculateTaskTotalsRecursively(task.sub_tasks);
|
||||
return {
|
||||
hours: acc.hours + (task.estimated_seconds || 0),
|
||||
cost: acc.cost + (task.actual_cost_from_logs || 0),
|
||||
fixedCost: acc.fixedCost + (task.fixed_cost || 0),
|
||||
totalBudget: acc.totalBudget + (task.total_budget || 0),
|
||||
totalActual: acc.totalActual + (task.total_actual || 0),
|
||||
variance: acc.variance + (task.variance || 0),
|
||||
total_time_logged: acc.total_time_logged + (task.total_time_logged_seconds || 0),
|
||||
estimated_cost: acc.estimated_cost + (task.estimated_cost || 0)
|
||||
hours: acc.hours + subtaskTotals.hours,
|
||||
cost: acc.cost + subtaskTotals.cost,
|
||||
fixedCost: acc.fixedCost + subtaskTotals.fixedCost,
|
||||
totalBudget: acc.totalBudget + subtaskTotals.totalBudget,
|
||||
totalActual: acc.totalActual + subtaskTotals.totalActual,
|
||||
variance: acc.variance + subtaskTotals.variance,
|
||||
total_time_logged: acc.total_time_logged + subtaskTotals.total_time_logged,
|
||||
estimated_cost: acc.estimated_cost + subtaskTotals.estimated_cost
|
||||
};
|
||||
} else {
|
||||
// Leaf task - use its individual values
|
||||
// Leaf task - calculate values from individual task properties
|
||||
const leafTotalActual = (task.actual_cost_from_logs || 0) + (task.fixed_cost || 0);
|
||||
return {
|
||||
hours: acc.hours + (task.estimated_seconds || 0),
|
||||
cost: acc.cost + (task.actual_cost_from_logs || 0),
|
||||
fixedCost: acc.fixedCost + (task.fixed_cost || 0),
|
||||
totalBudget: acc.totalBudget + (task.total_budget || 0),
|
||||
totalActual: acc.totalActual + (task.total_actual || 0),
|
||||
variance: acc.variance + (task.variance || 0),
|
||||
totalBudget: acc.totalBudget + (task.estimated_cost || 0),
|
||||
totalActual: acc.totalActual + leafTotalActual,
|
||||
variance: acc.variance + (leafTotalActual - (task.estimated_cost || 0)),
|
||||
total_time_logged: acc.total_time_logged + (task.total_time_logged_seconds || 0),
|
||||
estimated_cost: acc.estimated_cost + (task.estimated_cost || 0)
|
||||
};
|
||||
|
||||
@@ -539,8 +539,7 @@ const FinanceTable = ({
|
||||
|
||||
for (const task of taskList) {
|
||||
if (task.sub_tasks && task.sub_tasks.length > 0) {
|
||||
// Parent task with loaded subtasks - only count the subtasks recursively
|
||||
// This completely avoids the parent's aggregated values to prevent double counting
|
||||
// Parent task with loaded subtasks - only use subtasks values (no parent's own values)
|
||||
const subtaskTotals = calculateTaskTotalsRecursive(task.sub_tasks);
|
||||
totals.hours += subtaskTotals.hours;
|
||||
totals.total_time_logged += subtaskTotals.total_time_logged;
|
||||
@@ -552,14 +551,15 @@ const FinanceTable = ({
|
||||
totals.variance += subtaskTotals.variance;
|
||||
} else {
|
||||
// Leaf task or parent task without loaded subtasks - use its values directly
|
||||
const leafTotalActual = (task.actual_cost_from_logs || 0) + (task.fixed_cost || 0);
|
||||
totals.hours += task.estimated_seconds || 0;
|
||||
totals.total_time_logged += task.total_time_logged_seconds || 0;
|
||||
totals.estimated_cost += task.estimated_cost || 0;
|
||||
totals.actual_cost_from_logs += task.actual_cost_from_logs || 0;
|
||||
totals.fixed_cost += task.fixed_cost || 0;
|
||||
totals.total_budget += task.total_budget || 0;
|
||||
totals.total_actual += task.total_actual || 0;
|
||||
totals.variance += task.variance || 0;
|
||||
totals.total_budget += task.estimated_cost || 0;
|
||||
totals.total_actual += leafTotalActual;
|
||||
totals.variance += leafTotalActual - (task.estimated_cost || 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user