diff --git a/src/app/api/financialsummary/index.ts b/src/app/api/financialsummary/index.ts index adf1288..ecd5768 100644 --- a/src/app/api/financialsummary/index.ts +++ b/src/app/api/financialsummary/index.ts @@ -78,6 +78,24 @@ export interface FinancialSummaryByClient { numberOfRecords: number; } +export type FinancialByProject = { + id: number, + projectName: string, + projectCode: string, + team: string, + teamId: number, + custId: number, + customerName: string, + customerCode: string, + subsidiary: string, + totalFee: number, + totalBudget: number, + manhourExpense: number, + invoicedAmount: number, + paidAmount: number, + projectExpense: number, +} + export const preloadFinancialSummaryCard = () => { fetchFinancialSummaryCard(); }; @@ -102,3 +120,13 @@ export const fetchFinancialSummaryByProject = cache(async (endDate: string, team next: { tags: ["financialSummaryByProject"] }, }); }) + +export const fetchFinancialSummaryByProjectV2 = cache(async (teamId: number, endDate: string, startDate: string) => { + var endpoint = `${BASE_API_URL}/dashboard/getFinancialSummary-final?` + if (startDate.length > 0) endpoint += `&startDate=${startDate}` + if (endDate.length > 0) endpoint += `&endDate=${endDate}` + if (teamId > 0 ) endpoint += `&teamId=${teamId}` + return serverFetchJson(endpoint, { + next: { tags: ["financialSummaryByProject"] }, + }); +}) diff --git a/src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx b/src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx index 203bfdc..ea42ddf 100644 --- a/src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx +++ b/src/components/ProjectFinancialSummary/ProjectFinancialCard.tsx @@ -238,7 +238,7 @@ const ProjectFinancialCard: React.FC = ({ className="text-lg font-medium mx-5 mb-2" style={dataNegativeStyle} > - {CostPerformanceIndex} + {CostPerformanceIndex.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 3 })}
@@ -254,7 +254,7 @@ const ProjectFinancialCard: React.FC = ({ className="text-lg font-medium mx-5 mb-2" style={dataPositiveStyle} > - {CostPerformanceIndex} + {CostPerformanceIndex.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 3 })}
@@ -313,7 +313,7 @@ const ProjectFinancialCard: React.FC = ({ className="text-lg font-medium mx-5 mb-2" style={dataNegativeStyle} > - {ProjectedCPI} + {ProjectedCPI.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 3 })}
{"(k) = (b) / (d)"}
@@ -326,7 +326,7 @@ const ProjectFinancialCard: React.FC = ({ className="text-lg font-medium mx-5 mb-2" style={dataPositiveStyle} > - {ProjectedCPI} + {ProjectedCPI.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 3 })}
{"(k) = (b) / (d)"}
diff --git a/src/components/ProjectFinancialSummaryV2/FinancialSummary.tsx b/src/components/ProjectFinancialSummaryV2/FinancialSummary.tsx index 5232814..1f9ff95 100644 --- a/src/components/ProjectFinancialSummaryV2/FinancialSummary.tsx +++ b/src/components/ProjectFinancialSummaryV2/FinancialSummary.tsx @@ -1,5 +1,5 @@ "use client"; -import { fetchFinancialSummary, fetchFinancialSummaryByProject, FinancialSummaryByProject, FinancialSummaryType, FinancialSummaryByClient } from '@/app/api/financialsummary'; +import { fetchFinancialSummary, fetchFinancialSummaryByProject, FinancialSummaryByProject, FinancialSummaryType, FinancialSummaryByClient, FinancialByProject, fetchFinancialSummaryByProjectV2 } from '@/app/api/financialsummary'; import { Box, Card, CardContent, CardHeader, FormControl, InputLabel, Link, MenuItem, Select, Stack } from '@mui/material'; import { usePathname, useSearchParams } from 'next/navigation'; import { useRouter } from 'next/navigation'; @@ -8,78 +8,83 @@ import { useTranslation } from "react-i18next"; import ProjectFinancialCard from '../ProjectFinancialSummary/ProjectFinancialCard'; import dayjs from 'dayjs'; import { INPUT_DATE_FORMAT } from '@/app/utils/formatUtil'; -import { revalidateTag } from 'next/cache'; -import { revalidate } from '@/app/api/financialsummary/actions'; -import CircularProgress from '@mui/material/CircularProgress'; +import { SumOfByClient, SumOfByTeam, sumUpByClient, sumUpByTeam } from './gptFn'; import FinancialStatusByProject from './FinnancialStatusByProject'; -import { summarizeFinancialData } from './gptFn'; interface Props { - _financialSumm: FinancialSummaryType[], - _teamId: number | null + // _financialSumm: FinancialSummaryType[], + _teamId: number, + financialSummByProject: FinancialByProject[] } type InputDate = { - startDate: string | null; + startDate: string; endDate: string; } type DateParams = { - 1: InputDate; 2: InputDate; 3: InputDate; 4: InputDate; + 5: InputDate; } const FinancialSummaryPage: React.FC = ({ - _financialSumm, - _teamId + _teamId, + financialSummByProject }) => { const { t } = useTranslation(); - const searchParams = useSearchParams(); - const [financialSumm, setFinancialSumm] = useState(_financialSumm) - const [teamId, setTeamId] = useState(_teamId) - const [isCardClickedIndex, setIsCardClickedIndex] = useState(_financialSumm[0].team.id); const curr = useMemo(() => dayjs().format(INPUT_DATE_FORMAT), []) const currYear = useMemo(() => dayjs().get("year"), []) const startDate = useMemo(() => "10-01", []) const endDate = useMemo(() => "09-30", []) const currFinancialYear = useMemo(() => curr > `${currYear}-${startDate}` ? currYear + 1 : currYear, [currYear]) + const [mainData, setMainData] = useState(financialSummByProject) + const [byTeam, setByTeam] = useState(() => sumUpByTeam(mainData)) // do fetch to set + const [byProject, setByProject] = useState(financialSummByProject) + const [byClient, setByClient] = useState(() => sumUpByClient(mainData)) + const allTeam = useMemo(()=> { + var _allTeam: SumOfByTeam = { + id: 0, + team: "All Team", + totalFee: 0, + totalBudget: 0, + manhourExpense: 0, + projectExpense: 0, + invoicedAmount: 0, + paidAmount: 0, + activeProject: 0, + } + for (let i = 0; i < byTeam.length; i++) { + var curr = byTeam[i] + _allTeam["totalFee"] += curr.totalFee + _allTeam["totalBudget"] += curr.totalBudget + _allTeam["manhourExpense"] += curr.manhourExpense + _allTeam["projectExpense"] += curr.projectExpense + _allTeam["invoicedAmount"] += curr.invoicedAmount + _allTeam["paidAmount"] += curr.paidAmount + _allTeam["activeProject"] += curr.activeProject + } + return _allTeam + }, [mainData]) + + const [teamId, setTeamId] = useState(_teamId) + const [isCardClickedIndex, setIsCardClickedIndex] = useState(_teamId || 0); const [period, setPeriod] = useState(0); - const [isLoading, setIsLoading] = useState(true) - const [table1Data, setTable1Data] = useState([]) - const [table2Data, setTable2Data] = useState([]) + const dateMap: DateParams = useMemo(() => ({ - 1: {startDate: `${currFinancialYear-2}-${startDate}`, endDate: `${currFinancialYear-1}-${endDate}`}, - 2: {startDate: `${currFinancialYear-3}-${startDate}`, endDate: `${currFinancialYear-2}-${endDate}`}, - 3: {startDate: `${currFinancialYear-4}-${startDate}`, endDate: `${currFinancialYear-3}-${endDate}`}, - 4: {startDate: null, endDate: `${currFinancialYear-4}-${endDate}`}, + 2: {startDate: `${currFinancialYear-2}-${startDate}`, endDate: `${currFinancialYear-1}-${endDate}`}, + 3: {startDate: `${currFinancialYear-3}-${startDate}`, endDate: `${currFinancialYear-2}-${endDate}`}, + 4: {startDate: `${currFinancialYear-4}-${startDate}`, endDate: `${currFinancialYear-3}-${endDate}`}, + 5: {startDate: "", endDate: `${currFinancialYear-4}-${endDate}`}, }), [currYear, startDate, endDate]) - const [filter, setFilter] = useState(() => { - if (curr <= `${currYear}-${endDate}`) { - return ({ - startDate: `${currYear - 1}-${startDate}`, - endDate: `${currYear}-${endDate}` - }) - } else { - return ({ - startDate: `${currYear}-${startDate}`, - endDate: `${currFinancialYear}-${endDate}` - }) - } - }) - - const fetchHtmlTable = useCallback(async (teamId: number | null, endDate: string, startDate: string | null) => { - const tableData = await fetchFinancialSummary(endDate , teamId, startDate) - setFinancialSumm(tableData) - }, [fetchFinancialSummary]) - const fetchTable1Data = useCallback(async (teamId: number, endDate: string, startDate?: string) => { - const tableData = await fetchFinancialSummaryByProject(endDate , teamId.toString(), startDate) - setTable1Data(tableData) - const table2Data = summarizeFinancialData(table1Data) - console.log(table2Data) - setTable2Data(table2Data) - }, [fetchFinancialSummaryByProject]) + const fetchFinancialSummaryByProject = useCallback(async (endDate: string, startDate: string) => { + const data = await fetchFinancialSummaryByProjectV2(_teamId, endDate, startDate) + setMainData(data) + setByTeam(sumUpByTeam(data)) + setByProject(data) + setByClient(sumUpByClient(data)) + }, [setMainData, setByTeam, setByProject, setByClient]) const handleCardClick = useCallback((teamId: number) => { setIsCardClickedIndex(teamId) @@ -89,9 +94,12 @@ const FinancialSummaryPage: React.FC = ({ const handleFilter = useCallback((value: number) => { setPeriod(value) console.log(value) - var _startDate: string | null = "" + var _startDate: string = "" var _endDate = "" if (value == 0) { + _startDate = "" + _endDate == "" + } else if (value == 1) { if (curr <= `${currYear}-${endDate}`) { _startDate = `${currYear - 1}-${startDate}` _endDate = `${currYear}-${endDate}` @@ -103,27 +111,23 @@ const FinancialSummaryPage: React.FC = ({ _startDate = dateMap[value as keyof DateParams].startDate _endDate = dateMap[value as keyof DateParams].endDate } - setFilter({startDate: _startDate, endDate: _endDate}) + console.log(_startDate) + console.log(_endDate) + fetchFinancialSummaryByProject(_endDate, _startDate) + }, [isCardClickedIndex]) useEffect(() => { - if (financialSumm.length > 0) setIsLoading(false) - }, [financialSumm]) - - useEffect(() => { - console.log(teamId) - console.log(filter) - fetchHtmlTable(teamId, filter.endDate, filter.startDate) - if (teamId) { - const testing = fetchTable1Data(isCardClickedIndex, filter.endDate, filter.startDate ? filter.startDate : undefined) - console.log(testing) + if (teamId > 0) { + var filterByTeam = mainData.filter(item => item.teamId == teamId) + setByProject(filterByTeam) + setByClient(sumUpByClient(filterByTeam)) + } else { + setByProject(financialSummByProject) + setByClient(sumUpByClient(mainData)) } - }, [teamId, filter]) + }, [teamId]) - useEffect(() => { - console.log(searchParams.toString()) - }, [searchParams]) - return ( <> @@ -139,13 +143,15 @@ const FinancialSummaryPage: React.FC = ({ label="Age" onChange={(e) => handleFilter(Number(e.target.value))} > - {Array.from({ length: 5 }).map((_, i) => { + {Array.from({ length: 6 }).map((_, i) => { if (i == 0) { - return {`${currFinancialYear - i - 1} - ${currFinancialYear - i} (current)`} - } else if (i == 4) { - return {`< ${currYear - i}`} + return {`All`} + } else if (i == 1) { + return {`${currFinancialYear - i} - ${currFinancialYear - i + 1} (current year)`} + } else if (i == 5) { + return {`< ${currYear - i + 1}`} } else { - return {`${currFinancialYear - i - 1} - ${currFinancialYear - i}`} + return {`${currFinancialYear - i} - ${currFinancialYear - i + 1}`} } } )} @@ -154,44 +160,58 @@ const FinancialSummaryPage: React.FC = ({ - { !isLoading ? ( - <>
- {financialSumm.length > 0 && financialSumm.map((record:any) => ( -
handleCardClick(record.team.id)}> + {allTeam && +
handleCardClick(0)}> + = (allTeam.projectExpense + allTeam.invoicedAmount) ? "Positive" : "Negative"} + CostPerformanceIndex={allTeam.invoicedAmount/(allTeam.projectExpense + allTeam.invoicedAmount) || 0} + ProjectedCashFlowStatus={allTeam.totalFee >= (allTeam.projectExpense + allTeam.invoicedAmount) ? "Positive" : "Negative"} + ProjectedCPI={allTeam.totalFee/(allTeam.projectExpense + allTeam.invoicedAmount)} + ClickedIndex={isCardClickedIndex} + Index={0}/> +
} + {byTeam.length > 0 && byTeam.map((record) => ( +
handleCardClick(record.id)}> = (record.projectExpense + record.invoicedAmount) ? "Positive" : "Negative"} + CostPerformanceIndex={record.invoicedAmount/(record.projectExpense + record.invoicedAmount) || 0} + ProjectedCashFlowStatus={record.totalFee >= (record.projectExpense + record.invoicedAmount) ? "Positive" : "Negative"} + ProjectedCPI={record.totalFee/(record.projectExpense + record.invoicedAmount)} ClickedIndex={isCardClickedIndex} - Index={record.team.id}/> + Index={record.id}/>
))}
+ - - ) - : - - - - } ) } diff --git a/src/components/ProjectFinancialSummaryV2/FinancialSummaryWrapper.tsx b/src/components/ProjectFinancialSummaryV2/FinancialSummaryWrapper.tsx index 01a0946..7cb17e7 100644 --- a/src/components/ProjectFinancialSummaryV2/FinancialSummaryWrapper.tsx +++ b/src/components/ProjectFinancialSummaryV2/FinancialSummaryWrapper.tsx @@ -2,7 +2,7 @@ import React from "react"; import FinancialSummaryLoading from "./FinancialSummaryLoading"; import FinancialSummary from "./FinancialSummary"; import { fetchUserStaff, searchParamsProps } from "@/app/utils/fetchUtil"; -import { fetchFinancialSummary, fetchFinancialSummaryByProject, FinancialSummaryByProject, FinancialSummaryType } from "@/app/api/financialsummary"; +import { fetchFinancialSummary, fetchFinancialSummaryByProject, fetchFinancialSummaryByProjectV2, FinancialSummaryByProject, FinancialSummaryType } from "@/app/api/financialsummary"; import { Grid } from "@mui/material"; import FinancialStatusByProject from "./FinnancialStatusByProject"; @@ -16,48 +16,33 @@ interface SubComponents { const FinancialSummaryWrapper: React.FC & SubComponents = async ({ searchParams, }) => { - const curr = new Date() - const currYear = curr.getFullYear() - const start = "10-01" - const end = "09-30" - var defaultEnd: string - var defaultStart: string - if (curr.toISOString().split('T')[0] <= `${currYear}-${end}`) { - defaultStart = `${currYear-1}-${start}` - defaultEnd = `${currYear}-${end}` - } else { - defaultStart = `${currYear}-${start}` - defaultEnd = `${currYear+1}-${end}` - } - // const startDate = searchParams.startDate ?? defaultStart; - // const endDate = searchParams.endDate ?? defaultEnd; - const userStaff = await fetchUserStaff(); - const teamId = userStaff?.isTeamLead ? userStaff.teamId : null; - // let financialSumm: FinancialSummaryType[] = []; - // let financialSummByProject: FinancialSummaryByProject[] = []; - // if (startDate && endDate) { - // financialSumm = await fetchFinancialSummary(endDate as string, teamId, startDate as string); + // const curr = new Date() + // const currYear = curr.getFullYear() + // const start = "10-01" + // const end = "09-30" + // var defaultEnd: string + // var defaultStart: string + // if (curr.toISOString().split('T')[0] <= `${currYear}-${end}`) { + // defaultStart = `${currYear-1}-${start}` + // defaultEnd = `${currYear}-${end}` + // } else { + // defaultStart = `${currYear}-${start}` + // defaultEnd = `${currYear+1}-${end}` // } + const userStaff = await fetchUserStaff(); + const teamId = userStaff?.isTeamLead ? userStaff.teamId : 0; const [ - financialSumm + // financialSumm, + financialSummByProject ] = await Promise.all([ - fetchFinancialSummary(defaultEnd, teamId, defaultStart) + // fetchFinancialSummary(defaultEnd, teamId, defaultStart), + fetchFinancialSummaryByProjectV2(teamId, "", "") ]); - // if (teamId) { - // financialSummByProject = await fetchFinancialSummaryByProject(endDate as string, teamId.toString(), startDate as string) - // } else if (paramTeamId) { - // console.log(paramTeamId) - // console.log(startDate) - // console.log(endDate) - // financialSummByProject = await fetchFinancialSummaryByProject(endDate as string, paramTeamId as string, startDate as string) - // } - // console.log(financialSumm) // console.log(financialSummByProject) return ( - - {/* */} + ); }; diff --git a/src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx b/src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx index ecaffef..4b31874 100644 --- a/src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx +++ b/src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx @@ -3,6 +3,7 @@ import { FinancialSummaryByProject, FinancialSummaryByClient, + FinancialByProject, } from "@/app/api/financialsummary"; import SearchBox, { Criterion } from "../SearchBox"; import { useEffect, useMemo, useState } from "react"; @@ -10,31 +11,29 @@ import CustomDatagrid from "../CustomDatagrid"; import { useTranslation } from "react-i18next"; import { useRouter } from "next/navigation"; import { Box, Grid } from "@mui/material"; -import { summarizeFinancialData } from "./gptFn"; +import { SumOfByClient } from "./gptFn"; +// import { summarizeFinancialData } from "./gptFn"; interface Props { - financialSummByProject: FinancialSummaryByProject[]; -// financialSummByClient: FinancialSummaryByClient[]; + financialSummByProject: FinancialByProject[]; + financialSummByClient: SumOfByClient[]; } type SearchQuery = Partial>; type SearchParamNames = keyof SearchQuery; -type SearchQuery2 = Partial>; +type SearchQuery2 = Partial>; type SearchParamNames2 = keyof SearchQuery2; const FinancialStatusByProject: React.FC = ({ financialSummByProject, -// financialSummByClient, + financialSummByClient }) => { console.log(financialSummByProject); // console.log(financialSummByClient); const { t } = useTranslation("dashboard"); const router = useRouter(); const [filteredByProjectRows, setFilteredByProjectRows] = useState(financialSummByProject); - const [filteredByClientRows, setFilteredByClientRows] = useState(() => { - console.log(summarizeFinancialData(financialSummByProject)) - return summarizeFinancialData(financialSummByProject) ?? [] - }); + const [filteredByClientRows, setFilteredByClientRows] = useState(financialSummByClient); console.log(filteredByProjectRows); console.log(filteredByClientRows); @@ -59,8 +58,8 @@ console.log(filteredByProjectRows); useEffect(() => { setFilteredByProjectRows(financialSummByProject); - setFilteredByClientRows(summarizeFinancialData(financialSummByProject)) - }, [financialSummByProject]); + setFilteredByClientRows(financialSummByClient) + }, [financialSummByProject, financialSummByClient]); const columns1 = [ { @@ -118,9 +117,10 @@ console.log(filteredByProjectRows); headerName: "CPI", minWidth: 50, renderCell: (params: any) => { + var cpi = params.invoicedAmount/(params.projectExpense + params.invoicedAmount) || 0 return ( - = 1 ? greenColor : redColor}> - {params.row.cpi.toLocaleString(undefined, { + = 1 ? greenColor : redColor}> + {cpi.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -134,7 +134,8 @@ console.log(filteredByProjectRows); headerName: t("Projected Cash Flow Status"), minWidth: 100, renderCell: (params: any) => { - if (params.row.totalFee >= params.row.cumulativeExpenditure) { + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount + if (params.row.totalFee >= cumulativeExpenditure) { return {t("Positive")}; } else { return {t("Negative")}; @@ -147,11 +148,12 @@ console.log(filteredByProjectRows); headerName: t("Projected CPI"), minWidth: 50, renderCell: (params: any) => { + var projectedCpi = params.row.totalFee/(params.row.projectExpense + params.row.invoicedAmount) return ( = 1 ? greenColor : redColor} + className={projectedCpi >= 1 ? greenColor : redColor} > - {params.row.projectedCpi.toLocaleString(undefined, { + {projectedCpi.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -202,10 +204,11 @@ console.log(filteredByProjectRows); minWidth: 250, type: "number", renderCell: (params: any) => { + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount return ( $ - {params.row.cumulativeExpenditure.toLocaleString(undefined, { + {cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -274,10 +277,11 @@ console.log(filteredByProjectRows); minWidth: 250, type: "number", renderCell: (params: any) => { + var nonInvoiced = params.row.totalFee - params.row.invoicedAmount return ( $ - {params.row.nonInvoicedAmount.toLocaleString(undefined, { + {nonInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -286,8 +290,8 @@ console.log(filteredByProjectRows); }, }, { - id: "receivedAmount", - field: "receivedAmount", + id: "paidAmount", + field: "paidAmount", headerName: t("Total Received Amount") + t("HKD"), minWidth: 250, type: "number", @@ -295,7 +299,7 @@ console.log(filteredByProjectRows); return ( $ - {params.row.receivedAmount.toLocaleString(undefined, { + {params.row.paidAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -331,8 +335,8 @@ console.log(filteredByProjectRows); minWidth: 80, }, { - id: "numberOfRecords", - field: "numberOfRecords", + id: "sumOfProjects", + field: "sumOfProjects", headerName: t("Total Project Involved"), minWidth: 80, }, @@ -342,7 +346,8 @@ console.log(filteredByProjectRows); headerName: t("Cash Flow Status"), minWidth: 100, renderCell: (params: any) => { - return params.row.invoicedAmount >= params.row.cumulativeExpenditure ? + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount + return params.row.invoicedAmount >= cumulativeExpenditure ? {t("Positive")} : {t("Negative")} }, @@ -353,7 +358,8 @@ console.log(filteredByProjectRows); headerName: t("CPI"), minWidth: 50, renderCell: (params: any) => { - var cpi = params.row.cumulativeExpenditure != 0 ? params.row.invoicedAmount/params.row.cumulativeExpenditure : 0 + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount + var cpi = cumulativeExpenditure != 0 ? params.row.invoicedAmount/cumulativeExpenditure : 0 var cpiString = cpi.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, @@ -369,7 +375,8 @@ console.log(filteredByProjectRows); headerName: t("Projected Cash Flow Status"), minWidth: 100, renderCell: (params: any) => { - var status = params.row.invoiceAmount >= params.row.cumulativeExpenditure + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount + var status = params.row.invoiceAmount >= cumulativeExpenditure return status ? {t("Positive")} : {t("Negative")} @@ -381,7 +388,8 @@ console.log(filteredByProjectRows); headerName: t("Projected CPI"), minWidth: 50, renderCell: (params: any) => { - var projectCpi = params.row.cumulativeExpenditure != 0 ? params.row.totalFee/params.row.cumulativeExpenditure : 0 + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount + var projectCpi = cumulativeExpenditure != 0 ? params.row.totalFee/cumulativeExpenditure : 0 var projectCpiString = projectCpi.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, @@ -436,10 +444,11 @@ console.log(filteredByProjectRows); minWidth: 280, type: "number", renderCell: (params: any) => { + var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount return ( $ - {params.row.cumulativeExpenditure.toLocaleString(undefined, { + {cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -508,10 +517,11 @@ console.log(filteredByProjectRows); minWidth: 250, type: "number", renderCell: (params: any) => { + var uninvoiced = params.row.totalFee - params.row.invoicedAmount return ( $ - {params.row.nonInvoicedAmount.toLocaleString(undefined, { + {uninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} @@ -520,8 +530,8 @@ console.log(filteredByProjectRows); }, }, { - id: "receivedAmount", - field: "receivedAmount", + id: "paidAmount", + field: "paidAmount", headerName: t("Total Received Amount") + t("HKD"), minWidth: 250, type: "number", @@ -529,7 +539,7 @@ console.log(filteredByProjectRows); return ( $ - {params.row.receivedAmount.toLocaleString(undefined, { + {params.row.paidAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })} diff --git a/src/components/ProjectFinancialSummaryV2/gptFn.tsx b/src/components/ProjectFinancialSummaryV2/gptFn.tsx index 63c22ec..a38c8eb 100644 --- a/src/components/ProjectFinancialSummaryV2/gptFn.tsx +++ b/src/components/ProjectFinancialSummaryV2/gptFn.tsx @@ -1,40 +1,86 @@ -import { FinancialSummaryByProject, FinancialSummaryByClient } from "@/app/api/financialsummary"; +import { FinancialSummaryByProject, FinancialSummaryByClient, FinancialSummaryType, FinancialByProject } from "@/app/api/financialsummary"; +export type SumOfByTeam = { + id: number, + team: string, + totalFee: number, + totalBudget: number, + manhourExpense: number, + projectExpense: number, + invoicedAmount: number, + paidAmount: number, + activeProject: number, +} -export function summarizeFinancialData(data: FinancialSummaryByProject[]): FinancialSummaryByClient[] { - const result = data.reduce>((acc, item) => { +export type SumOfByClient = { + id: number, // custId + customerCode: string, + customerName: string, + totalFee: number, + totalBudget: number, + manhourExpense: number, + projectExpense: number, + invoicedAmount: number, + paidAmount: number, + sumOfProjects: number, +} +export function sumUpByClient(data: FinancialByProject[]): SumOfByClient[] { + const result = data.reduce>((acc, item) => { if (!acc[item.custId]) { acc[item.custId] = { - id: item.custId, // Set id to custId - customerName: item.customerName, // First item's customerName - customerCode: item.customerCode, // First item's customerCode - subsidiaryName: item.subsidiaryName, // First item's subsidiaryName + id: item.custId, + customerCode: item.customerName, + customerName: item.customerCode, totalFee: 0, totalBudget: 0, - cumulativeExpenditure: 0, manhourExpense: 0, projectExpense: 0, invoicedAmount: 0, - nonInvoicedAmount: 0, - receivedAmount: 0, - numberOfRecords: 0, // Initialize record count + paidAmount: 0, + sumOfProjects: 0 }; } - // Sum the numeric fields acc[item.custId].totalFee += item.totalFee; acc[item.custId].totalBudget += item.totalBudget; - acc[item.custId].cumulativeExpenditure += item.cumulativeExpenditure; acc[item.custId].manhourExpense += item.manhourExpense; acc[item.custId].projectExpense += item.projectExpense; acc[item.custId].invoicedAmount += item.invoicedAmount; - acc[item.custId].nonInvoicedAmount += item.nonInvoicedAmount; - acc[item.custId].receivedAmount += item.receivedAmount; - acc[item.custId].numberOfRecords += 1; // Increment record count + acc[item.custId].paidAmount += item.paidAmount; + acc[item.custId].sumOfProjects += 1; + + return acc; + }, {}); + return Object.values(result); +} +export function sumUpByTeam(data: FinancialByProject[]): SumOfByTeam[] { + const result = data.reduce>((acc, item) => { + if (!acc[item.teamId]) { + acc[item.teamId] = { + id: item.teamId, + team: item.team, + totalFee: 0, + totalBudget: 0, + manhourExpense: 0, + projectExpense: 0, + invoicedAmount: 0, + paidAmount: 0, + activeProject: 0 + }; + } + + // Sum the numeric fields + acc[item.teamId].totalFee += item.totalFee; + acc[item.teamId].totalBudget += item.totalBudget; + acc[item.teamId].manhourExpense += item.manhourExpense; + acc[item.teamId].projectExpense += item.projectExpense; + acc[item.teamId].invoicedAmount += item.invoicedAmount; + acc[item.teamId].paidAmount += item.paidAmount; + acc[item.teamId].activeProject += 1; return acc; }, {}); // Convert the result object to an array return Object.values(result); -} \ No newline at end of file +}