| @@ -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')) { | ||||