feat(task-breakdown-api): implement task financial breakdown API and related enhancements

- Added a new API endpoint `GET /api/project-finance/task/:id/breakdown` to retrieve detailed financial breakdown for individual tasks, including labor hours and costs grouped by job roles.
- Introduced a new SQL migration to add a `fixed_cost` column to the tasks table for improved financial calculations.
- Updated the project finance controller to handle task breakdown logic, including calculations for estimated and actual costs.
- Enhanced frontend components to integrate the new task breakdown API, providing real-time financial data in the finance drawer.
- Updated localization files to reflect changes in financial terminology across English, Spanish, and Portuguese.
- Implemented Redux state management for selected tasks in the finance drawer.
This commit is contained in:
chamikaJ
2025-05-26 16:36:25 +05:30
parent 399d8b420a
commit b0ed3f67e8
26 changed files with 1330 additions and 455 deletions

View File

@@ -1,6 +1,6 @@
import { projectFinanceApiService } from '@/api/project-finance-ratecard/project-finance.api.service';
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { IProjectFinanceGroup, IProjectFinanceTask } from '@/types/project/project-finance.types';
import { IProjectFinanceGroup, IProjectFinanceTask, IProjectRateCard } from '@/types/project/project-finance.types';
type FinanceTabType = 'finance' | 'ratecard';
type GroupTypes = 'status' | 'priority' | 'phases';
@@ -10,6 +10,7 @@ interface ProjectFinanceState {
activeGroup: GroupTypes;
loading: boolean;
taskGroups: IProjectFinanceGroup[];
projectRateCards: IProjectRateCard[];
}
// Utility functions for frontend calculations
@@ -67,6 +68,7 @@ const initialState: ProjectFinanceState = {
activeGroup: 'status',
loading: false,
taskGroups: [],
projectRateCards: [],
};
export const fetchProjectFinances = createAsyncThunk(
@@ -77,6 +79,14 @@ export const fetchProjectFinances = createAsyncThunk(
}
);
export const updateTaskFixedCostAsync = createAsyncThunk(
'projectFinances/updateTaskFixedCostAsync',
async ({ taskId, groupId, fixedCost }: { taskId: string; groupId: string; fixedCost: number }) => {
await projectFinanceApiService.updateTaskFixedCost(taskId, fixedCost);
return { taskId, groupId, fixedCost };
}
);
export const projectFinancesSlice = createSlice({
name: 'projectFinances',
initialState,
@@ -140,10 +150,26 @@ export const projectFinancesSlice = createSlice({
})
.addCase(fetchProjectFinances.fulfilled, (state, action) => {
state.loading = false;
state.taskGroups = action.payload;
state.taskGroups = action.payload.groups;
state.projectRateCards = action.payload.project_rate_cards;
})
.addCase(fetchProjectFinances.rejected, (state) => {
state.loading = false;
})
.addCase(updateTaskFixedCostAsync.fulfilled, (state, action) => {
const { taskId, groupId, fixedCost } = action.payload;
const group = state.taskGroups.find(g => g.group_id === groupId);
if (group) {
const task = group.tasks.find(t => t.id === taskId);
if (task) {
task.fixed_cost = fixedCost;
// Recalculate task costs after updating fixed cost
const { totalBudget, totalActual, variance } = calculateTaskCosts(task);
task.total_budget = totalBudget;
task.total_actual = totalActual;
task.variance = variance;
}
}
});
},
});