feat(finance): implement project finance and rate card management features

- Added new controllers for managing project finance and rate cards, including CRUD operations for rate card roles and project finance tasks.
- Introduced API routes for project finance and rate card functionalities, enhancing the backend structure.
- Developed frontend components for displaying and managing project finance data, including a finance drawer and rate card settings.
- Enhanced localization files to support new UI elements and ensure consistency across multiple languages.
- Implemented utility functions for handling man-days and financial calculations, improving overall functionality.
This commit is contained in:
chamikaJ
2025-07-24 15:23:34 +05:30
parent 4b54f2cc17
commit 4ffc3465e3
51 changed files with 10202 additions and 169 deletions

View File

@@ -5,6 +5,7 @@ import i18n from '@/i18n';
// Import core components synchronously to avoid suspense in main tabs
import ProjectViewEnhancedBoard from '@/pages/projects/projectView/enhancedBoard/project-view-enhanced-board';
import TaskListV2 from '@/components/task-list-v2/TaskListV2';
import ProjectViewFinance from '@/pages/projects/projectView/finance/ProjectViewFinance';
// Lazy load less critical components
const ProjectViewInsights = React.lazy(
@@ -117,6 +118,16 @@ export const tabItems: TabItems[] = [
React.createElement(ProjectViewUpdates)
),
},
{
index: 6,
key: 'finance',
label: getTabLabel('finance'),
element: React.createElement(
Suspense,
{ fallback: React.createElement(InlineSuspenseFallback) },
React.createElement(ProjectViewFinance)
),
},
];
// Function to update tab labels when language changes

View File

@@ -0,0 +1,127 @@
export enum FinanceTableColumnKeys {
TASK = 'task',
MEMBERS = 'members',
HOURS = 'hours',
MAN_DAYS = 'man_days',
TOTAL_TIME_LOGGED = 'total_time_logged',
ESTIMATED_COST = 'estimated_cost',
COST = 'cost',
FIXED_COST = 'fixedCost',
TOTAL_BUDGET = 'totalBudget',
TOTAL_ACTUAL = 'totalActual',
VARIANCE = 'variance',
}
type FinanceTableColumnsType = {
key: FinanceTableColumnKeys;
name: string;
width: number;
type: 'string' | 'hours' | 'currency' | 'man_days' | 'effort_variance';
render?: (value: any) => React.ReactNode;
};
// finance table columns
export const financeTableColumns: FinanceTableColumnsType[] = [
{
key: FinanceTableColumnKeys.TASK,
name: 'taskColumn',
width: 240,
type: 'string',
},
{
key: FinanceTableColumnKeys.MEMBERS,
name: 'membersColumn',
width: 120,
type: 'string',
},
{
key: FinanceTableColumnKeys.HOURS,
name: 'hoursColumn',
width: 100,
type: 'hours',
},
{
key: FinanceTableColumnKeys.MAN_DAYS,
name: 'manDaysColumn',
width: 100,
type: 'man_days',
},
{
key: FinanceTableColumnKeys.TOTAL_TIME_LOGGED,
name: 'totalTimeLoggedColumn',
width: 120,
type: 'hours',
},
{
key: FinanceTableColumnKeys.ESTIMATED_COST,
name: 'estimatedCostColumn',
width: 120,
type: 'currency',
},
{
key: FinanceTableColumnKeys.COST,
name: 'costColumn',
width: 120,
type: 'currency',
},
{
key: FinanceTableColumnKeys.FIXED_COST,
name: 'fixedCostColumn',
width: 120,
type: 'currency',
},
{
key: FinanceTableColumnKeys.TOTAL_BUDGET,
name: 'totalBudgetedCostColumn',
width: 120,
type: 'currency',
},
{
key: FinanceTableColumnKeys.TOTAL_ACTUAL,
name: 'totalActualCostColumn',
width: 120,
type: 'currency',
},
{
key: FinanceTableColumnKeys.VARIANCE,
name: 'varianceColumn',
width: 120,
type: 'currency',
},
];
// Function to get columns based on calculation method
export const getFinanceTableColumns = (
calculationMethod: 'hourly' | 'man_days' = 'hourly'
): FinanceTableColumnsType[] => {
return financeTableColumns.filter(column => {
// Always show these columns
if (
[
FinanceTableColumnKeys.TASK,
FinanceTableColumnKeys.MEMBERS,
FinanceTableColumnKeys.TOTAL_TIME_LOGGED,
FinanceTableColumnKeys.ESTIMATED_COST,
FinanceTableColumnKeys.COST,
FinanceTableColumnKeys.FIXED_COST,
FinanceTableColumnKeys.TOTAL_BUDGET,
FinanceTableColumnKeys.TOTAL_ACTUAL,
FinanceTableColumnKeys.VARIANCE,
].includes(column.key)
) {
return true;
}
// Show hours column only for hourly calculation
if (column.key === FinanceTableColumnKeys.HOURS) {
return calculationMethod === 'hourly';
}
// Show man days columns only for man days calculation
if ([FinanceTableColumnKeys.MAN_DAYS].includes(column.key)) {
return calculationMethod === 'man_days';
}
return false;
});
};

View File

@@ -1,3 +1,4 @@
import RateCardSettings from '@/pages/settings/rate-card-settings/RateCardSettings';
import {
BankOutlined,
FileZipOutlined,
@@ -12,20 +13,33 @@ import {
UserOutlined,
UserSwitchOutlined,
BulbOutlined,
DollarCircleOutlined
} from '@/shared/antd-imports';
import React, { ReactNode, lazy } from 'react';
const ProfileSettings = lazy(() => import('../../pages/settings/profile/profile-settings'));
const NotificationsSettings = lazy(() => import('../../pages/settings/notifications/notifications-settings'));
const NotificationsSettings = lazy(
() => import('../../pages/settings/notifications/notifications-settings')
);
const ClientsSettings = lazy(() => import('../../pages/settings/clients/clients-settings'));
const JobTitlesSettings = lazy(() => import('@/pages/settings/job-titles/job-titles-settings'));
const LabelsSettings = lazy(() => import('../../pages/settings/labels/labels-settings'));
const CategoriesSettings = lazy(() => import('../../pages/settings/categories/categories-settings'));
const ProjectTemplatesSettings = lazy(() => import('@/pages/settings/project-templates/project-templates-settings'));
const TaskTemplatesSettings = lazy(() => import('@/pages/settings/task-templates/task-templates-settings'));
const TeamMembersSettings = lazy(() => import('@/pages/settings/team-members/team-members-settings'));
const CategoriesSettings = lazy(
() => import('../../pages/settings/categories/categories-settings')
);
const ProjectTemplatesSettings = lazy(
() => import('@/pages/settings/project-templates/project-templates-settings')
);
const TaskTemplatesSettings = lazy(
() => import('@/pages/settings/task-templates/task-templates-settings')
);
const TeamMembersSettings = lazy(
() => import('@/pages/settings/team-members/team-members-settings')
);
const TeamsSettings = lazy(() => import('../../pages/settings/teams/teams-settings'));
const ChangePassword = lazy(() => import('@/pages/settings/change-password/change-password'));
const LanguageAndRegionSettings = lazy(() => import('@/pages/settings/language-and-region/language-and-region-settings'));
const LanguageAndRegionSettings = lazy(
() => import('@/pages/settings/language-and-region/language-and-region-settings')
);
const AppearanceSettings = lazy(() => import('@/pages/settings/appearance/appearance-settings'));
// type of menu item in settings sidebar
@@ -132,6 +146,13 @@ export const settingsItems: SettingMenuItems[] = [
element: React.createElement(TeamMembersSettings),
adminOnly: true,
},
{
key: 'ratecard',
name: 'Rate Card',
endpoint: 'ratecard',
icon: React.createElement(DollarCircleOutlined),
element: React.createElement(RateCardSettings),
},
{
key: 'teams',
name: 'teams',