@@ -131,6 +131,9 @@ export function convertLocaleStringToNumber(numberString: string): number { | |||||
} | } | ||||
export function timestampToDateString(timestamp: string): string { | export function timestampToDateString(timestamp: string): string { | ||||
if (timestamp === null){ | |||||
return "-" | |||||
} | |||||
const date = new Date(timestamp); | const date = new Date(timestamp); | ||||
const year = date.getFullYear(); | const year = date.getFullYear(); | ||||
const month = String(date.getMonth() + 1).padStart(2, "0"); | const month = String(date.getMonth() + 1).padStart(2, "0"); | ||||
@@ -344,7 +344,7 @@ const ProjectClientDetails: React.FC<Props> = ({ | |||||
/> | /> | ||||
</Grid> | </Grid> | ||||
<Grid item xs={6}> | |||||
{/* <Grid item xs={6}> | |||||
<Checkbox | <Checkbox | ||||
{...register("isClpProject")} | {...register("isClpProject")} | ||||
checked={Boolean(watch("isClpProject"))} | checked={Boolean(watch("isClpProject"))} | ||||
@@ -353,7 +353,7 @@ const ProjectClientDetails: React.FC<Props> = ({ | |||||
<Typography variant="overline" display="inline"> | <Typography variant="overline" display="inline"> | ||||
{t("CLP Project")} | {t("CLP Project")} | ||||
</Typography> | </Typography> | ||||
</Grid> | |||||
</Grid> */} | |||||
</Grid> | </Grid> | ||||
</Box> | </Box> | ||||
@@ -86,7 +86,7 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
const formData = new FormData(); | const formData = new FormData(); | ||||
formData.append('multipartFileList', file); | formData.append('multipartFileList', file); | ||||
const response = await importInvoices(formData); | |||||
const response = await importIssuedInovice(formData); | |||||
// response: status, message, projectList, emptyRowList, invoiceList | // response: status, message, projectList, emptyRowList, invoiceList | ||||
console.log(response) | console.log(response) | ||||
@@ -236,7 +236,7 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
{ name: "projectName", label: t("Project Name") }, | { name: "projectName", label: t("Project Name") }, | ||||
{ name: "team", label: t("Team") }, | { name: "team", label: t("Team") }, | ||||
{ name: "issuedDate", label: t("Issue Date") }, | { name: "issuedDate", label: t("Issue Date") }, | ||||
{ name: "receivedAmount", label: t("Amount (HKD)") }, | |||||
{ name: "issuedAmount", label: t("Amount (HKD)") }, | |||||
{ name: "receiptDate", label: t("Settle Date") }, | { name: "receiptDate", label: t("Settle Date") }, | ||||
{ name: "receivedAmount", label: t("Actual Received Amount (HKD)") }, | { name: "receivedAmount", label: t("Actual Received Amount (HKD)") }, | ||||
], | ], | ||||
@@ -271,8 +271,8 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
flexWrap="wrap" | flexWrap="wrap" | ||||
spacing={2} | spacing={2} | ||||
> | > | ||||
{/* <ButtonGroup variant="contained"> */} | |||||
{/* <Button startIcon={<FileUploadIcon />} variant="contained" component="label"> | |||||
<ButtonGroup variant="contained"> | |||||
<Button startIcon={<FileUploadIcon />} variant="contained" component="label"> | |||||
<input | <input | ||||
id='importExcel' | id='importExcel' | ||||
type='file' | type='file' | ||||
@@ -291,9 +291,9 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
onChange={(event) => {handleRecImportClick(event)}} | onChange={(event) => {handleRecImportClick(event)}} | ||||
/> | /> | ||||
{t("Import Invoice Amount Receive Summary")} | {t("Import Invoice Amount Receive Summary")} | ||||
</Button> */} | |||||
{/* </ButtonGroup> */} | |||||
<Button startIcon={<FileUploadIcon />} variant="contained" component="label"> | |||||
</Button> | |||||
</ButtonGroup> | |||||
{/* <Button startIcon={<FileUploadIcon />} variant="contained" component="label"> | |||||
<input | <input | ||||
id='importExcel' | id='importExcel' | ||||
type='file' | type='file' | ||||
@@ -302,7 +302,7 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
onChange={(event) => {handleImportClick(event)}} | onChange={(event) => {handleImportClick(event)}} | ||||
/> | /> | ||||
{t("Import Invoice Summary")} | {t("Import Invoice Summary")} | ||||
</Button> | |||||
</Button> */} | |||||
</Stack> | </Stack> | ||||
{ | { | ||||
// tabIndex == 0 && | // tabIndex == 0 && | ||||
@@ -56,9 +56,9 @@ const InvoiceSearchWrapper: React.FC & SubComponents = async () => { | |||||
projectName: invoice.projectName, | projectName: invoice.projectName, | ||||
team: invoice.team, | team: invoice.team, | ||||
issuedDate: timestampToDateString(invoice.invoiceDate)!!, | issuedDate: timestampToDateString(invoice.invoiceDate)!!, | ||||
receiptDate: timestampToDateString(invoice.receiptDate??0)!!, | |||||
receiptDate: timestampToDateString(invoice.receiptDate??null)!!, | |||||
issuedAmount: moneyFormatter.format(invoice.issueAmount), | issuedAmount: moneyFormatter.format(invoice.issueAmount), | ||||
receivedAmount: moneyFormatter.format(invoice.paidAmount) | |||||
receivedAmount: invoice.paidAmount === null ? "-" : moneyFormatter.format(invoice.paidAmount) | |||||
} | } | ||||
}) | }) | ||||
@@ -67,16 +67,16 @@ import { | |||||
MAINTAIN_GROUP, | MAINTAIN_GROUP, | ||||
MAINTAIN_HOLIDAY, | MAINTAIN_HOLIDAY, | ||||
VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, | VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, | ||||
GENERATE_LATE_START_REPORTS, | |||||
GENERATE_LATE_START_REPORT, | |||||
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | ||||
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | ||||
GENERATE_COST_ANT_EXPENSE_REPORT, | |||||
GENERATE_COST_AND_EXPENSE_REPORT, | |||||
GENERATE_PROJECT_COMPLETION_REPORT, | GENERATE_PROJECT_COMPLETION_REPORT, | ||||
GENERATE_PROJECT_PANDL_REPORT, | GENERATE_PROJECT_PANDL_REPORT, | ||||
GENERATE_FINANCIAL_STATUS_REPORT, | GENERATE_FINANCIAL_STATUS_REPORT, | ||||
GENERATE_PROJECT_CASH_FLOW_REPORT, | GENERATE_PROJECT_CASH_FLOW_REPORT, | ||||
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | ||||
GENERATE_CROSS_TEAM_CHARGE_REPORT, | |||||
GENERATE_CROSS_TEAM_CHARGE_REPORT | |||||
} from "@/middleware"; | } from "@/middleware"; | ||||
import { SessionWithAbilities } from "../AppBar/NavigationToggle"; | import { SessionWithAbilities } from "../AppBar/NavigationToggle"; | ||||
import { authOptions } from "@/config/authConfig"; | import { authOptions } from "@/config/authConfig"; | ||||
@@ -190,16 +190,16 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
label: "Analysis Report", | label: "Analysis Report", | ||||
path: "", | path: "", | ||||
isHidden: ![ | isHidden: ![ | ||||
GENERATE_LATE_START_REPORTS, | |||||
GENERATE_LATE_START_REPORT, | |||||
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | ||||
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | ||||
GENERATE_COST_ANT_EXPENSE_REPORT, | |||||
GENERATE_COST_AND_EXPENSE_REPORT, | |||||
GENERATE_PROJECT_COMPLETION_REPORT, | GENERATE_PROJECT_COMPLETION_REPORT, | ||||
GENERATE_PROJECT_PANDL_REPORT, | GENERATE_PROJECT_PANDL_REPORT, | ||||
GENERATE_FINANCIAL_STATUS_REPORT, | GENERATE_FINANCIAL_STATUS_REPORT, | ||||
GENERATE_PROJECT_CASH_FLOW_REPORT, | GENERATE_PROJECT_CASH_FLOW_REPORT, | ||||
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | ||||
GENERATE_CROSS_TEAM_CHARGE_REPORT, | |||||
GENERATE_CROSS_TEAM_CHARGE_REPORT | |||||
].some((ability) => | ].some((ability) => | ||||
abilities!.includes(ability), | abilities!.includes(ability), | ||||
), | ), | ||||
@@ -208,7 +208,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
icon: <Analytics />, | icon: <Analytics />, | ||||
label: "Late Start Report", | label: "Late Start Report", | ||||
path: "/analytics/LateStartReport", | path: "/analytics/LateStartReport", | ||||
isHidden: ![GENERATE_LATE_START_REPORTS].some((ability) => | |||||
isHidden: ![GENERATE_LATE_START_REPORT].some((ability) => | |||||
abilities!.includes(ability), | abilities!.includes(ability), | ||||
), | ), | ||||
}, | }, | ||||
@@ -232,7 +232,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
icon: <Analytics />, | icon: <Analytics />, | ||||
label: "Cost and Expense Report", | label: "Cost and Expense Report", | ||||
path: "/analytics/CostandExpenseReport", | path: "/analytics/CostandExpenseReport", | ||||
isHidden: ![GENERATE_COST_ANT_EXPENSE_REPORT].some((ability) => | |||||
isHidden: ![GENERATE_COST_AND_EXPENSE_REPORT].some((ability) => | |||||
abilities!.includes(ability), | abilities!.includes(ability), | ||||
), | ), | ||||
}, | }, | ||||
@@ -954,7 +954,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
className="text-sm font-medium ml-5" | className="text-sm font-medium ml-5" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
Accounts Receivable | |||||
Remaining Budget | |||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5 mb-2" | className="text-lg font-medium ml-5 mb-2" | ||||
@@ -362,7 +362,7 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
const startCount = weeklyPlanned[i].startCount | const startCount = weeklyPlanned[i].startCount | ||||
const endCount = weeklyPlanned[i].endCount | const endCount = weeklyPlanned[i].endCount | ||||
for (var j = 0; j < weeklyPlanned[i].searchDuration; j++) { | for (var j = 0; j < weeklyPlanned[i].searchDuration; j++) { | ||||
if (j >= startCount && j < endCount) { | |||||
if (j >= startCount && j <= endCount) { | |||||
weeklyPlannedSubList.push(weeklyPlanned[i].AverageManhours) | weeklyPlannedSubList.push(weeklyPlanned[i].AverageManhours) | ||||
} else { | } else { | ||||
weeklyPlannedSubList.push(0) | weeklyPlannedSubList.push(0) | ||||
@@ -503,7 +503,8 @@ const StaffUtilization: React.FC<Props> = ({ abilities, staff }) => { | |||||
const fetchMonthlyUnsubmittedData = async () => { | const fetchMonthlyUnsubmittedData = async () => { | ||||
const fetchResult = await fetchMonthlyUnsubmit(teamUnsubmitTeamId, unsubmitMonthlyFromValue.format('YYYY-MM-DD'), unsubmitMonthlyToValue.endOf('month').format('YYYY-MM-DD'), holidayDates); | |||||
const fetchResult = await fetchMonthlyUnsubmit(teamUnsubmitTeamId, unsubmitMonthlyFromValue.startOf('month').format('YYYY-MM-DD'), unsubmitMonthlyToValue.endOf('month').format('YYYY-MM-DD'), holidayDates); | |||||
const result = [] | const result = [] | ||||
const staffList = [] | const staffList = [] | ||||
var maxValue = 5 | var maxValue = 5 | ||||
@@ -59,16 +59,16 @@ export const [ | |||||
VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, | VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, | ||||
MAINTAIN_NORMAL_STAFF_WORKSPACE, | MAINTAIN_NORMAL_STAFF_WORKSPACE, | ||||
MAINTAIN_MANAGEMENT_STAFF_WORKSPACE, | MAINTAIN_MANAGEMENT_STAFF_WORKSPACE, | ||||
GENERATE_LATE_START_REPORTS, | |||||
GENERATE_LATE_START_REPORT, | |||||
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | ||||
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | ||||
GENERATE_COST_ANT_EXPENSE_REPORT, | |||||
GENERATE_COST_AND_EXPENSE_REPORT, | |||||
GENERATE_PROJECT_COMPLETION_REPORT, | GENERATE_PROJECT_COMPLETION_REPORT, | ||||
GENERATE_PROJECT_PANDL_REPORT, | GENERATE_PROJECT_PANDL_REPORT, | ||||
GENERATE_FINANCIAL_STATUS_REPORT, | GENERATE_FINANCIAL_STATUS_REPORT, | ||||
GENERATE_PROJECT_CASH_FLOW_REPORT, | GENERATE_PROJECT_CASH_FLOW_REPORT, | ||||
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | ||||
GENERATE_CROSS_TEAM_CHARGE_REPORT, | |||||
GENERATE_CROSS_TEAM_CHARGE_REPORT | |||||
] = [ | ] = [ | ||||
'MAINTAIN_USER', | 'MAINTAIN_USER', | ||||
'MAINTAIN_TIMESHEET', | 'MAINTAIN_TIMESHEET', | ||||
@@ -109,16 +109,16 @@ export const [ | |||||
'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING', | 'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING', | ||||
'MAINTAIN_NORMAL_STAFF_WORKSPACE', | 'MAINTAIN_NORMAL_STAFF_WORKSPACE', | ||||
'MAINTAIN_MANAGEMENT_STAFF_WORKSPACE', | 'MAINTAIN_MANAGEMENT_STAFF_WORKSPACE', | ||||
'GENERATE_LATE_START_REPORTS', | |||||
'GENERATE_PROJECT_POTENTIAL_DELAY_REPORT', | |||||
'GENERATE_RESOURCE_OVERCONSUMPTION_REPORT', | |||||
'GENERATE_COST_ANT_EXPENSE_REPORT', | |||||
'GENERATE_PROJECT_COMPLETION_REPORT', | |||||
'GENERATE_PROJECT_P&L_REPORT', | |||||
'GENERATE_FINANCIAL_STATUS_REPORT', | |||||
'GENERATE_PROJECT_CASH_FLOW_REPORT', | |||||
'GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT', | |||||
'GENERATE_CROSS_TEAM_CHARGE_REPORT', | |||||
'G_LATE_START_REPORT', | |||||
'G_PROJECT_POTENTIAL_DELAY_REPORT', | |||||
'G_RESOURCE_OVERCONSUMPTION_REPORT', | |||||
'G_COST_AND_EXPENSE_REPORT', | |||||
'G_PROJECT_COMPLETION_REPORT', | |||||
'G_PROJECT_P&L_REPORT', | |||||
'G_FINANCIAL_STATUS_REPORT', | |||||
'G_PROJECT_CASH_FLOW_REPORT', | |||||
'G_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT', | |||||
'G_CROSS_TEAM_CHARGE_REPORT' | |||||
] | ] | ||||
const PRIVATE_ROUTES = [ | const PRIVATE_ROUTES = [ | ||||
@@ -243,20 +243,21 @@ export default async function middleware( | |||||
if (req.nextUrl.pathname.startsWith('/analytics')) { | if (req.nextUrl.pathname.startsWith('/analytics')) { | ||||
isAuth = [ | isAuth = [ | ||||
GENERATE_LATE_START_REPORTS, | |||||
GENERATE_LATE_START_REPORT, | |||||
GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, | ||||
GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, | ||||
GENERATE_COST_ANT_EXPENSE_REPORT, | |||||
GENERATE_COST_AND_EXPENSE_REPORT, | |||||
GENERATE_PROJECT_COMPLETION_REPORT, | GENERATE_PROJECT_COMPLETION_REPORT, | ||||
GENERATE_PROJECT_PANDL_REPORT, | GENERATE_PROJECT_PANDL_REPORT, | ||||
GENERATE_FINANCIAL_STATUS_REPORT, | GENERATE_FINANCIAL_STATUS_REPORT, | ||||
GENERATE_PROJECT_CASH_FLOW_REPORT, | GENERATE_PROJECT_CASH_FLOW_REPORT, | ||||
GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, | ||||
GENERATE_CROSS_TEAM_CHARGE_REPORT,].some((ability) => abilities.includes(ability)); | |||||
GENERATE_CROSS_TEAM_CHARGE_REPORT | |||||
].some((ability) => abilities.includes(ability)); | |||||
} | } | ||||
if (req.nextUrl.pathname.startsWith('/analytics/LateStartReport')) { | if (req.nextUrl.pathname.startsWith('/analytics/LateStartReport')) { | ||||
isAuth = [GENERATE_LATE_START_REPORTS].some((ability) => abilities.includes(ability)); | |||||
isAuth = [GENERATE_LATE_START_REPORT].some((ability) => abilities.includes(ability)); | |||||
} | } | ||||
if (req.nextUrl.pathname.startsWith('/analytics/ProjectPotentialDelayReport')) { | if (req.nextUrl.pathname.startsWith('/analytics/ProjectPotentialDelayReport')) { | ||||
@@ -268,7 +269,7 @@ export default async function middleware( | |||||
} | } | ||||
if (req.nextUrl.pathname.startsWith('/analytics/CostandExpenseReport')) { | if (req.nextUrl.pathname.startsWith('/analytics/CostandExpenseReport')) { | ||||
isAuth = [GENERATE_COST_ANT_EXPENSE_REPORT].some((ability) => abilities.includes(ability)); | |||||
isAuth = [GENERATE_COST_AND_EXPENSE_REPORT].some((ability) => abilities.includes(ability)); | |||||
} | } | ||||
if (req.nextUrl.pathname.startsWith('/analytics/ProjectCompletionReport')) { | if (req.nextUrl.pathname.startsWith('/analytics/ProjectCompletionReport')) { | ||||