feat(project-finance): add billable filter functionality to project finance queries

- Introduced a `billable_filter` query parameter to filter tasks based on their billable status (billable, non-billable, or all).
- Updated the project finance controller to construct SQL queries with billable conditions based on the filter.
- Enhanced the frontend components to support billable filtering in project finance views and exports.
- Added corresponding translations for filter options in multiple languages.
- Refactored related API services to accommodate the new filtering logic.
This commit is contained in:
chamikaJ
2025-06-06 12:02:53 +05:30
parent ba2ecb2d85
commit 791cbe22df
19 changed files with 965 additions and 499 deletions

View File

@@ -5,10 +5,12 @@ import { parseTimeToSeconds } from '@/utils/timeUtils';
type FinanceTabType = 'finance' | 'ratecard';
type GroupTypes = 'status' | 'priority' | 'phases';
type BillableFilterType = 'all' | 'billable' | 'non-billable';
interface ProjectFinanceState {
activeTab: FinanceTabType;
activeGroup: GroupTypes;
billableFilter: BillableFilterType;
loading: boolean;
taskGroups: IProjectFinanceGroup[];
projectRateCards: IProjectRateCard[];
@@ -65,6 +67,7 @@ const calculateGroupTotals = (tasks: IProjectFinanceTask[]) => {
const initialState: ProjectFinanceState = {
activeTab: 'finance',
activeGroup: 'status',
billableFilter: 'billable',
loading: false,
taskGroups: [],
projectRateCards: [],
@@ -73,24 +76,24 @@ const initialState: ProjectFinanceState = {
export const fetchProjectFinances = createAsyncThunk(
'projectFinances/fetchProjectFinances',
async ({ projectId, groupBy }: { projectId: string; groupBy: GroupTypes }) => {
const response = await projectFinanceApiService.getProjectTasks(projectId, groupBy);
async ({ projectId, groupBy, billableFilter }: { projectId: string; groupBy: GroupTypes; billableFilter?: BillableFilterType }) => {
const response = await projectFinanceApiService.getProjectTasks(projectId, groupBy, billableFilter);
return response.body;
}
);
export const fetchProjectFinancesSilent = createAsyncThunk(
'projectFinances/fetchProjectFinancesSilent',
async ({ projectId, groupBy }: { projectId: string; groupBy: GroupTypes }) => {
const response = await projectFinanceApiService.getProjectTasks(projectId, groupBy);
async ({ projectId, groupBy, billableFilter }: { projectId: string; groupBy: GroupTypes; billableFilter?: BillableFilterType }) => {
const response = await projectFinanceApiService.getProjectTasks(projectId, groupBy, billableFilter);
return response.body;
}
);
export const fetchSubTasks = createAsyncThunk(
'projectFinances/fetchSubTasks',
async ({ projectId, parentTaskId }: { projectId: string; parentTaskId: string }) => {
const response = await projectFinanceApiService.getSubTasks(projectId, parentTaskId);
async ({ projectId, parentTaskId, billableFilter }: { projectId: string; parentTaskId: string; billableFilter?: BillableFilterType }) => {
const response = await projectFinanceApiService.getSubTasks(projectId, parentTaskId, billableFilter);
return { parentTaskId, subTasks: response.body };
}
);
@@ -113,6 +116,9 @@ export const projectFinancesSlice = createSlice({
setActiveGroup: (state, action: PayloadAction<GroupTypes>) => {
state.activeGroup = action.payload;
},
setBillableFilter: (state, action: PayloadAction<BillableFilterType>) => {
state.billableFilter = action.payload;
},
updateTaskFixedCost: (state, action: PayloadAction<{ taskId: string; groupId: string; fixedCost: number }>) => {
const { taskId, groupId, fixedCost } = action.payload;
const group = state.taskGroups.find(g => g.group_id === groupId);
@@ -224,6 +230,7 @@ export const projectFinancesSlice = createSlice({
export const {
setActiveTab,
setActiveGroup,
setBillableFilter,
updateTaskFixedCost,
updateTaskEstimatedCost,
updateTaskTimeLogged,