Browse Source

update financial summary V2

tags/Baseline_180220205_Frontend
cyril.tsui 7 months ago
parent
commit
eecf73aad9
2 changed files with 135 additions and 63 deletions
  1. +28
    -1
      src/app/api/financialsummary/actions.ts
  2. +107
    -62
      src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx

+ 28
- 1
src/app/api/financialsummary/actions.ts View File

@@ -6,7 +6,8 @@ import { Dayjs } from "dayjs";
import { cache } from "react"; import { cache } from "react";
import { FileResponse } from "../reports/actions"; import { FileResponse } from "../reports/actions";
import { revalidateTag } from "next/cache"; import { revalidateTag } from "next/cache";

import { SumOfByClient } from "@/components/ProjectFinancialSummaryV2/gptFn";
import { FinancialByProject } from ".";


export interface FinancialSummaryByClientResult { export interface FinancialSummaryByClientResult {
teamId:number; teamId:number;
@@ -144,6 +145,32 @@ export const exportFinancialSummaryByProjectExcel = cache(async (data: ExportFin
return reportBlob return reportBlob
}) })


export const exportFinancialSummaryV2ByClientExcel = cache(async (data: SumOfByClient[]) => {
const reportBlob = await serverFetchBlob<FileResponse>(
`${BASE_API_URL}/dashboard/exportFinancialSummaryV2ByClientExcel`,
{
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
},
);

return reportBlob
})

export const exportFinancialSummaryV2ByProjectExcel = cache(async (data: FinancialByProject[]) => {
const reportBlob = await serverFetchBlob<FileResponse>(
`${BASE_API_URL}/dashboard/exportFinancialSummaryV2ByProjectExcel`,
{
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
},
);

return reportBlob
})

export const revalidate = async(tag: string) => { export const revalidate = async(tag: string) => {
revalidateTag(tag) revalidateTag(tag)
} }

+ 107
- 62
src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx View File

@@ -8,8 +8,10 @@ import { useEffect, useMemo, useState } from "react";
import CustomDatagrid from "../CustomDatagrid"; import CustomDatagrid from "../CustomDatagrid";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { Box } from "@mui/material";
import { Box, Card, CardHeader } from "@mui/material";
import { SumOfByClient } from "./gptFn"; import { SumOfByClient } from "./gptFn";
import { exportFinancialSummaryV2ByClientExcel, exportFinancialSummaryV2ByProjectExcel } from "@/app/api/financialsummary/actions";
import { downloadFile } from "@/app/utils/commonUtil";
// import { summarizeFinancialData } from "./gptFn"; // import { summarizeFinancialData } from "./gptFn";


interface Props { interface Props {
@@ -99,7 +101,8 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("Cash Flow Status"), headerName: t("Cash Flow Status"),
minWidth: 80, minWidth: 80,
renderCell: (params: any) => { renderCell: (params: any) => {
if (params.row.invoicedAmount >= params.row.cumulativeExpenditure) {
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
if (params.row.invoicedAmount >= cumulativeExpenditure) {
return <span className={greenColor}>{t("Positive")}</span>; return <span className={greenColor}>{t("Positive")}</span>;
} else { } else {
return <span className={redColor}>{t("Negative")}</span>; return <span className={redColor}>{t("Negative")}</span>;
@@ -112,7 +115,8 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: "CPI", headerName: "CPI",
minWidth: 50, minWidth: 50,
renderCell: (params: any) => { renderCell: (params: any) => {
var cpi = params.row.invoicedAmount/(params.row.projectExpense + params.row.invoicedAmount) || 0
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
var cpi = params.row.invoicedAmount/cumulativeExpenditure || 0
return ( return (
<span className={cpi >= 1 ? greenColor : redColor}> <span className={cpi >= 1 ? greenColor : redColor}>
{cpi.toLocaleString(undefined, { {cpi.toLocaleString(undefined, {
@@ -129,7 +133,7 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("Projected Cash Flow Status"), headerName: t("Projected Cash Flow Status"),
minWidth: 100, minWidth: 100,
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
if (params.row.totalFee >= cumulativeExpenditure) { if (params.row.totalFee >= cumulativeExpenditure) {
return <span className={greenColor}>{t("Positive")}</span>; return <span className={greenColor}>{t("Positive")}</span>;
} else { } else {
@@ -143,7 +147,8 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("Projected CPI"), headerName: t("Projected CPI"),
minWidth: 50, minWidth: 50,
renderCell: (params: any) => { renderCell: (params: any) => {
var projectedCpi = params.row.totalFee/(params.row.projectExpense + params.row.invoicedAmount) == Infinity ? 'N/A' : params.row.totalFee/(params.row.projectExpense + params.row.invoicedAmount)
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
var projectedCpi = params.row.totalFee/cumulativeExpenditure == Infinity ? 'N/A' : params.row.totalFee/cumulativeExpenditure
return ( return (
<span <span
className={(typeof projectedCpi == "number" && projectedCpi >= 1 ? greenColor : redColor)} className={(typeof projectedCpi == "number" && projectedCpi >= 1 ? greenColor : redColor)}
@@ -199,7 +204,7 @@ const FinancialStatusByProject: React.FC<Props> = ({
minWidth: 250, minWidth: 250,
type: "number", type: "number",
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
return ( return (
<span> <span>
$ $
@@ -341,7 +346,7 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("Cash Flow Status"), headerName: t("Cash Flow Status"),
minWidth: 100, minWidth: 100,
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
return params.row.invoicedAmount >= cumulativeExpenditure ? return params.row.invoicedAmount >= cumulativeExpenditure ?
<span className={greenColor}>{t("Positive")}</span> <span className={greenColor}>{t("Positive")}</span>
: <span className={redColor}>{t("Negative")}</span> : <span className={redColor}>{t("Negative")}</span>
@@ -353,7 +358,7 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("CPI"), headerName: t("CPI"),
minWidth: 50, minWidth: 50,
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
var cpi = cumulativeExpenditure != 0 ? params.row.invoicedAmount/cumulativeExpenditure : 0 var cpi = cumulativeExpenditure != 0 ? params.row.invoicedAmount/cumulativeExpenditure : 0
var cpiString = cpi.toLocaleString(undefined, { var cpiString = cpi.toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
@@ -370,8 +375,8 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("Projected Cash Flow Status"), headerName: t("Projected Cash Flow Status"),
minWidth: 100, minWidth: 100,
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var status = params.row.invoiceAmount >= cumulativeExpenditure
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
var status = params.row.totalFee >= cumulativeExpenditure
return status ? return status ?
<span className={greenColor}>{t("Positive")}</span> <span className={greenColor}>{t("Positive")}</span>
: <span className={redColor}>{t("Negative")}</span> : <span className={redColor}>{t("Negative")}</span>
@@ -383,7 +388,7 @@ const FinancialStatusByProject: React.FC<Props> = ({
headerName: t("Projected CPI"), headerName: t("Projected CPI"),
minWidth: 50, minWidth: 50,
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
var projectCpi = cumulativeExpenditure != 0 ? params.row.totalFee/cumulativeExpenditure : 0 var projectCpi = cumulativeExpenditure != 0 ? params.row.totalFee/cumulativeExpenditure : 0
var projectCpiString = projectCpi.toLocaleString(undefined, { var projectCpiString = projectCpi.toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
@@ -439,7 +444,7 @@ const FinancialStatusByProject: React.FC<Props> = ({
minWidth: 280, minWidth: 280,
type: "number", type: "number",
renderCell: (params: any) => { renderCell: (params: any) => {
var cumulativeExpenditure = params.row.projectExpense + params.row.invoicedAmount
var cumulativeExpenditure = params.row.projectExpense + params.row.manhourExpense
return ( return (
<span> <span>
$ $
@@ -544,64 +549,104 @@ const FinancialStatusByProject: React.FC<Props> = ({
}, },
]; ];


const handleExportByClient = async () => {
const response = await exportFinancialSummaryV2ByClientExcel(filteredByClientRows)
if (response) {
downloadFile(new Uint8Array(response.blobValue), response.filename!!)
}
console.log(filteredByClientRows)
};

const handleExportByProject = async () => {
const response = await exportFinancialSummaryV2ByProjectExcel(filteredByProjectRows)
if (response) {
downloadFile(new Uint8Array(response.blobValue), response.filename!!)
}
console.log(filteredByProjectRows)
};

return ( return (
<> <>
<Box sx={{ mt: 3 }}> <Box sx={{ mt: 3 }}>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
console.log(query)
if (query.projectCode.length > 0 || query.projectName.length > 0) {
setFilteredByProjectRows(
financialSummByProject.filter(
(cp) =>
cp.projectCode.toLowerCase().includes(query.projectCode.trim().toLowerCase()) &&
cp.projectName.toLowerCase().includes(query.projectName.trim().toLowerCase())
),
);
} else {
setFilteredByProjectRows(financialSummByProject)
}
}}
/>
<div style={{ display: "inline-block", width: "99%", marginLeft: 10 }}>
<CustomDatagrid
rows={filteredByProjectRows}
columns={columns1}
columnWidth={200}
dataGridHeight={300}
loading={isLoading}
<Card className="mt-5">
<div style={{display:"inline-block"}}>
<CardHeader className="text-slate-500" title= {t("Financial Status (by Project)")}/>
</div>
<div style={{display:"inline-block"}}>
{filteredByProjectRows.length > 0 && (
<button onClick={handleExportByProject} className="hover:cursor-pointer hover:bg-lime-50 text-base bg-transparent border-lime-600 text-lime-600 border-solid rounded-md w-36">
{t("Export Excel")}
</button>
)}
</div>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
console.log(query)
if (query.projectCode.length > 0 || query.projectName.length > 0) {
setFilteredByProjectRows(
financialSummByProject.filter(
(cp) =>
cp.projectCode.toLowerCase().includes(query.projectCode.trim().toLowerCase()) &&
cp.projectName.toLowerCase().includes(query.projectName.trim().toLowerCase())
),
);
} else {
setFilteredByProjectRows(financialSummByProject)
}
}}
/> />
</div>
<div style={{ display: "inline-block", width: "99%", marginLeft: 10 }}>
<CustomDatagrid
rows={filteredByProjectRows}
columns={columns1}
columnWidth={200}
dataGridHeight={300}
loading={isLoading}
/>
</div>
{/* <SearchResults<StaffResult> items={filteredStaff} columns={columns} /> */} {/* <SearchResults<StaffResult> items={filteredStaff} columns={columns} /> */}
</Card>
</Box> </Box>
<Box sx={{ mt: 3 }}> <Box sx={{ mt: 3 }}>
<SearchBox
criteria={searchCriteria2}
onSearch={(query) => {
console.log(query)
if (query.customerCode.length > 0 || query.customerName.length > 0) {
setFilteredByClientRows(
financialSummByClient.filter(
(cp) =>
cp.customerCode.toLowerCase().includes(query.customerCode.trim().toLowerCase()) &&
cp.customerName.toLowerCase().includes(query.customerName.trim().toLowerCase())
),
);
} else {
setFilteredByClientRows(financialSummByClient)
}
}}
/>
<div style={{ display: "inline-block", width: "99%", marginLeft: 10 }}>
<CustomDatagrid
rows={filteredByClientRows}
columns={columns2}
columnWidth={200}
dataGridHeight={300}
loading={isLoading}
<Card className="mt-5">
<div style={{display:"inline-block"}}>
<CardHeader className="text-slate-500" title= {t("Financial Status (by Client)")}/>
</div>
<div style={{display:"inline-block"}}>
{filteredByProjectRows.length > 0 && (
<button onClick={handleExportByClient} className="hover:cursor-pointer hover:bg-lime-50 text-base bg-transparent border-lime-600 text-lime-600 border-solid rounded-md w-36">
{t("Export Excel")}
</button>
)}
</div>
<SearchBox
criteria={searchCriteria2}
onSearch={(query) => {
console.log(query)
if (query.customerCode.length > 0 || query.customerName.length > 0) {
setFilteredByClientRows(
financialSummByClient.filter(
(cp) =>
cp.customerCode.toLowerCase().includes(query.customerCode.trim().toLowerCase()) &&
cp.customerName.toLowerCase().includes(query.customerName.trim().toLowerCase())
),
);
} else {
setFilteredByClientRows(financialSummByClient)
}
}}
/> />
</div>
<div style={{ display: "inline-block", width: "99%", marginLeft: 10 }}>
<CustomDatagrid
rows={filteredByClientRows}
columns={columns2}
columnWidth={200}
dataGridHeight={300}
loading={isLoading}
/>
</div>
</Card>
</Box> </Box>
</> </>
); );


Loading…
Cancel
Save