Ver a proveniência

update financial summary V2

tags/Baseline_180220205_Frontend
cyril.tsui há 7 meses
ascendente
cometimento
eecf73aad9
2 ficheiros alterados com 135 adições e 63 eliminações
  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 Ver ficheiro

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

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

export interface FinancialSummaryByClientResult {
teamId:number;
@@ -144,6 +145,32 @@ export const exportFinancialSummaryByProjectExcel = cache(async (data: ExportFin
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) => {
revalidateTag(tag)
}

+ 107
- 62
src/components/ProjectFinancialSummaryV2/FinnancialStatusByProject.tsx Ver ficheiro

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

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


Carregando…
Cancelar
Guardar