fix(finance-table): refine budget and variance calculations for improved accuracy
- Updated budget calculations to consistently include fixed costs across all tasks. - Adjusted variance logic to align with the new budget calculations, ensuring accurate financial reporting. - Increased save delay for fixed cost input to 5 seconds, allowing users more time to edit values. - Added text selection on input focus for better user experience.
This commit is contained in:
@@ -85,13 +85,14 @@ const FinanceTableWrapper: React.FC<FinanceTableWrapperProps> = ({ activeTablesL
|
|||||||
} else {
|
} else {
|
||||||
// Leaf task - calculate values from individual task properties
|
// Leaf task - calculate values from individual task properties
|
||||||
const leafTotalActual = (task.actual_cost_from_logs || 0) + (task.fixed_cost || 0);
|
const leafTotalActual = (task.actual_cost_from_logs || 0) + (task.fixed_cost || 0);
|
||||||
|
const leafTotalBudget = (task.estimated_cost || 0) + (task.fixed_cost || 0);
|
||||||
return {
|
return {
|
||||||
hours: acc.hours + (task.estimated_seconds || 0),
|
hours: acc.hours + (task.estimated_seconds || 0),
|
||||||
cost: acc.cost + (task.actual_cost_from_logs || 0),
|
cost: acc.cost + (task.actual_cost_from_logs || 0),
|
||||||
fixedCost: acc.fixedCost + (task.fixed_cost || 0),
|
fixedCost: acc.fixedCost + (task.fixed_cost || 0),
|
||||||
totalBudget: acc.totalBudget + (task.estimated_cost || 0),
|
totalBudget: acc.totalBudget + leafTotalBudget,
|
||||||
totalActual: acc.totalActual + leafTotalActual,
|
totalActual: acc.totalActual + leafTotalActual,
|
||||||
variance: acc.variance + (leafTotalActual - (task.estimated_cost || 0)),
|
variance: acc.variance + (leafTotalActual - leafTotalBudget),
|
||||||
total_time_logged: acc.total_time_logged + (task.total_time_logged_seconds || 0),
|
total_time_logged: acc.total_time_logged + (task.total_time_logged_seconds || 0),
|
||||||
estimated_cost: acc.estimated_cost + (task.estimated_cost || 0)
|
estimated_cost: acc.estimated_cost + (task.estimated_cost || 0)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -230,10 +230,9 @@ const FinanceTable = ({
|
|||||||
// Only save if the value actually changed
|
// Only save if the value actually changed
|
||||||
if (newFixedCost !== currentFixedCost && value !== null) {
|
if (newFixedCost !== currentFixedCost && value !== null) {
|
||||||
handleFixedCostChange(value, taskId);
|
handleFixedCostChange(value, taskId);
|
||||||
setSelectedTask(null);
|
// Don't close the input automatically - let user explicitly close it
|
||||||
setEditingFixedCostValue(null);
|
|
||||||
}
|
}
|
||||||
}, 1000); // Save after 1 second of inactivity
|
}, 5000); // Save after 5 seconds of inactivity
|
||||||
};
|
};
|
||||||
|
|
||||||
// Immediate save function (for enter/blur)
|
// Immediate save function (for enter/blur)
|
||||||
@@ -442,6 +441,10 @@ const FinanceTable = ({
|
|||||||
// Immediate save on enter
|
// Immediate save on enter
|
||||||
immediateSaveFixedCost(editingFixedCostValue, task.id);
|
immediateSaveFixedCost(editingFixedCostValue, task.id);
|
||||||
}}
|
}}
|
||||||
|
onFocus={(e) => {
|
||||||
|
// Select all text when input is focused
|
||||||
|
e.target.select();
|
||||||
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
style={{ width: '100%', textAlign: 'right', fontSize: Math.max(12, 14 - level * 0.5) }}
|
style={{ width: '100%', textAlign: 'right', fontSize: Math.max(12, 14 - level * 0.5) }}
|
||||||
formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
||||||
@@ -472,22 +475,27 @@ const FinanceTable = ({
|
|||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
);
|
);
|
||||||
case FinanceTableColumnKeys.VARIANCE:
|
case FinanceTableColumnKeys.VARIANCE:
|
||||||
|
const taskTotalBudgetForVariance = (task.estimated_cost || 0) + (task.fixed_cost || 0);
|
||||||
|
const taskTotalActualForVariance = (task.actual_cost_from_logs || 0) + (task.fixed_cost || 0);
|
||||||
|
const taskVariance = taskTotalActualForVariance - taskTotalBudgetForVariance;
|
||||||
return (
|
return (
|
||||||
<Typography.Text
|
<Typography.Text
|
||||||
style={{
|
style={{
|
||||||
color: task.variance > 0 ? '#FF0000' : '#6DC376',
|
color: taskVariance > 0 ? '#FF0000' : '#6DC376',
|
||||||
fontSize: Math.max(12, 14 - level * 0.5)
|
fontSize: Math.max(12, 14 - level * 0.5)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{task.variance < 0 ? '+' + formatNumber(Math.abs(task.variance)) :
|
{taskVariance < 0 ? '+' + formatNumber(Math.abs(taskVariance)) :
|
||||||
task.variance > 0 ? '-' + formatNumber(task.variance) :
|
taskVariance > 0 ? '-' + formatNumber(taskVariance) :
|
||||||
formatNumber(task.variance)}
|
formatNumber(taskVariance)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
);
|
);
|
||||||
case FinanceTableColumnKeys.TOTAL_BUDGET:
|
case FinanceTableColumnKeys.TOTAL_BUDGET:
|
||||||
return <Typography.Text style={{ fontSize: Math.max(12, 14 - level * 0.5) }}>{formatNumber(task.total_budget)}</Typography.Text>;
|
const taskTotalBudget = (task.estimated_cost || 0) + (task.fixed_cost || 0);
|
||||||
|
return <Typography.Text style={{ fontSize: Math.max(12, 14 - level * 0.5) }}>{formatNumber(taskTotalBudget)}</Typography.Text>;
|
||||||
case FinanceTableColumnKeys.TOTAL_ACTUAL:
|
case FinanceTableColumnKeys.TOTAL_ACTUAL:
|
||||||
return <Typography.Text style={{ fontSize: Math.max(12, 14 - level * 0.5) }}>{formatNumber(task.total_actual)}</Typography.Text>;
|
const taskTotalActual = (task.actual_cost_from_logs || 0) + (task.fixed_cost || 0);
|
||||||
|
return <Typography.Text style={{ fontSize: Math.max(12, 14 - level * 0.5) }}>{formatNumber(taskTotalActual)}</Typography.Text>;
|
||||||
case FinanceTableColumnKeys.COST:
|
case FinanceTableColumnKeys.COST:
|
||||||
return <Typography.Text style={{ fontSize: Math.max(12, 14 - level * 0.5) }}>{formatNumber(task.actual_cost_from_logs || 0)}</Typography.Text>;
|
return <Typography.Text style={{ fontSize: Math.max(12, 14 - level * 0.5) }}>{formatNumber(task.actual_cost_from_logs || 0)}</Typography.Text>;
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user