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:
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user