|
@@ -10,13 +10,14 @@ import { Button, ButtonGroup, Stack, Tab, Tabs, TabsProps } from "@mui/material" |
|
|
import FileDownloadIcon from '@mui/icons-material/FileDownload'; |
|
|
import FileDownloadIcon from '@mui/icons-material/FileDownload'; |
|
|
import FileUploadIcon from '@mui/icons-material/FileUpload'; |
|
|
import FileUploadIcon from '@mui/icons-material/FileUpload'; |
|
|
import { dateInRange, downloadFile } from "@/app/utils/commonUtil"; |
|
|
import { dateInRange, downloadFile } from "@/app/utils/commonUtil"; |
|
|
import { importIssuedInovice, importReceivedInovice } from "@/app/api/invoices/actions"; |
|
|
|
|
|
|
|
|
import { importInvoices, importIssuedInovice, importReceivedInovice } from "@/app/api/invoices/actions"; |
|
|
import { errorDialogWithContent, successDialog } from "../Swal/CustomAlerts"; |
|
|
import { errorDialogWithContent, successDialog } from "../Swal/CustomAlerts"; |
|
|
import { issuedInvoiceList, issuedInvoiceResult, issuedInvoiceSearchForm, receivedInvoiceList, receivedInvoiceSearchForm } from "@/app/api/invoices"; |
|
|
|
|
|
|
|
|
import { invoiceList, issuedInvoiceList, issuedInvoiceResult, issuedInvoiceSearchForm, receivedInvoiceList, receivedInvoiceSearchForm } from "@/app/api/invoices"; |
|
|
|
|
|
|
|
|
interface Props { |
|
|
interface Props { |
|
|
issuedInvoice: issuedInvoiceList[]; |
|
|
issuedInvoice: issuedInvoiceList[]; |
|
|
receivedInvoice: receivedInvoiceList[]; |
|
|
receivedInvoice: receivedInvoiceList[]; |
|
|
|
|
|
invoices: invoiceList[]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
type SearchQuery = Partial<Omit<issuedInvoiceSearchForm, "id">>; |
|
|
type SearchQuery = Partial<Omit<issuedInvoiceSearchForm, "id">>; |
|
@@ -25,19 +26,21 @@ type SearchParamNames = keyof SearchQuery; |
|
|
type SearchQuery2 = Partial<Omit<receivedInvoiceSearchForm, "id">>; |
|
|
type SearchQuery2 = Partial<Omit<receivedInvoiceSearchForm, "id">>; |
|
|
type SearchParamNames2 = keyof SearchQuery2; |
|
|
type SearchParamNames2 = keyof SearchQuery2; |
|
|
|
|
|
|
|
|
const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
|
|
|
|
|
|
const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoices }) => { |
|
|
const { t } = useTranslation("invoices"); |
|
|
const { t } = useTranslation("invoices"); |
|
|
const [tabIndex, setTabIndex] = useState(0); |
|
|
const [tabIndex, setTabIndex] = useState(0); |
|
|
|
|
|
|
|
|
const [filteredIssuedInvoices, setFilteredIssuedInvoices] = useState(issuedInvoice); |
|
|
const [filteredIssuedInvoices, setFilteredIssuedInvoices] = useState(issuedInvoice); |
|
|
const [filteredReceivedInvoices, setFilteredReceivedInvoices] = useState(receivedInvoice); |
|
|
const [filteredReceivedInvoices, setFilteredReceivedInvoices] = useState(receivedInvoice); |
|
|
|
|
|
const [filteredIvoices, setFilterInovices] = useState(invoices); |
|
|
|
|
|
|
|
|
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( |
|
|
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( |
|
|
() => [ |
|
|
() => [ |
|
|
{ label: t("Invoice No"), paramName: "invoiceNo", type: "text" }, |
|
|
{ label: t("Invoice No"), paramName: "invoiceNo", type: "text" }, |
|
|
{ label: t("Project Code"), paramName: "projectCode", type: "text" }, |
|
|
{ label: t("Project Code"), paramName: "projectCode", type: "text" }, |
|
|
{ label: t("Invoice Date"), label2: t("Invoice Date To"), paramName: "invoiceDate", type: "dateRange" }, |
|
|
|
|
|
{ label: t("Due Date"), label2: t("Due Date To"), paramName: "dueDate", type: "dateRange" }, |
|
|
|
|
|
|
|
|
{ label: t("Team"), paramName: "team", type: "text" }, |
|
|
|
|
|
{ label: t("Issue Date"), label2: t("Issue Date To"), paramName: "invoiceDate", type: "dateRange" }, |
|
|
|
|
|
{ label: t("Settle Date"), label2: t("Settle Date To"), paramName: "dueDate", type: "dateRange" }, |
|
|
], |
|
|
], |
|
|
[t, issuedInvoice], |
|
|
[t, issuedInvoice], |
|
|
); |
|
|
); |
|
@@ -52,8 +55,9 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const onReset = useCallback(() => { |
|
|
const onReset = useCallback(() => { |
|
|
setFilteredIssuedInvoices(issuedInvoice); |
|
|
|
|
|
}, [issuedInvoice]); |
|
|
|
|
|
|
|
|
// setFilteredIssuedInvoices(issuedInvoice); |
|
|
|
|
|
setFilterInovices(invoices) |
|
|
|
|
|
}, [invoices]); |
|
|
|
|
|
|
|
|
function concatListOfObject(obj: any[]): string { |
|
|
function concatListOfObject(obj: any[]): string { |
|
|
return obj.map(obj => `Cannot find "${obj.paymentMilestone}" in ${obj.invoiceNo}`).join(", ") |
|
|
return obj.map(obj => `Cannot find "${obj.paymentMilestone}" in ${obj.invoiceNo}`).join(", ") |
|
@@ -82,7 +86,7 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
const formData = new FormData(); |
|
|
const formData = new FormData(); |
|
|
formData.append('multipartFileList', file); |
|
|
formData.append('multipartFileList', file); |
|
|
|
|
|
|
|
|
const response = await importIssuedInovice(formData); |
|
|
|
|
|
|
|
|
const response = await importInvoices(formData); |
|
|
// response: status, message, projectList, emptyRowList, invoiceList |
|
|
// response: status, message, projectList, emptyRowList, invoiceList |
|
|
|
|
|
|
|
|
console.log(response) |
|
|
console.log(response) |
|
@@ -225,6 +229,20 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
[t], |
|
|
[t], |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const combinedColumns = useMemo<Column<invoiceList>[]>( |
|
|
|
|
|
() => [ |
|
|
|
|
|
{ name: "invoiceNo", label: t("Invoice No") }, |
|
|
|
|
|
{ name: "projectCode", label: t("Project Code") }, |
|
|
|
|
|
{ name: "projectName", label: t("Project Name") }, |
|
|
|
|
|
{ name: "team", label: t("Team") }, |
|
|
|
|
|
{ name: "issuedDate", label: t("Issue Date") }, |
|
|
|
|
|
{ name: "receivedAmount", label: t("Amount (HKD)") }, |
|
|
|
|
|
{ name: "receiptDate", label: t("Settle Date") }, |
|
|
|
|
|
{ name: "receivedAmount", label: t("Actual Received Amount (HKD)") }, |
|
|
|
|
|
], |
|
|
|
|
|
[t] |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
function isDateInRange(dateToCheck: string, startDate: string, endDate: string): boolean { |
|
|
function isDateInRange(dateToCheck: string, startDate: string, endDate: string): boolean { |
|
|
|
|
|
|
|
|
if ((!startDate || startDate === "Invalid Date") && (!endDate || endDate === "Invalid Date")) { |
|
|
if ((!startDate || startDate === "Invalid Date") && (!endDate || endDate === "Invalid Date")) { |
|
@@ -254,7 +272,7 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
spacing={2} |
|
|
spacing={2} |
|
|
> |
|
|
> |
|
|
{/* <ButtonGroup variant="contained"> */} |
|
|
{/* <ButtonGroup variant="contained"> */} |
|
|
<Button startIcon={<FileUploadIcon />} variant="contained" component="label"> |
|
|
|
|
|
|
|
|
{/* <Button startIcon={<FileUploadIcon />} variant="contained" component="label"> |
|
|
<input |
|
|
<input |
|
|
id='importExcel' |
|
|
id='importExcel' |
|
|
type='file' |
|
|
type='file' |
|
@@ -273,29 +291,40 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
onChange={(event) => {handleRecImportClick(event)}} |
|
|
onChange={(event) => {handleRecImportClick(event)}} |
|
|
/> |
|
|
/> |
|
|
{t("Import Invoice Amount Receive Summary")} |
|
|
{t("Import Invoice Amount Receive Summary")} |
|
|
</Button> |
|
|
|
|
|
|
|
|
</Button> */} |
|
|
{/* </ButtonGroup> */} |
|
|
{/* </ButtonGroup> */} |
|
|
|
|
|
<Button startIcon={<FileUploadIcon />} variant="contained" component="label"> |
|
|
|
|
|
<input |
|
|
|
|
|
id='importExcel' |
|
|
|
|
|
type='file' |
|
|
|
|
|
accept='.xlsx, .csv' |
|
|
|
|
|
hidden |
|
|
|
|
|
onChange={(event) => {handleImportClick(event)}} |
|
|
|
|
|
/> |
|
|
|
|
|
{t("Import Invoice Summary")} |
|
|
|
|
|
</Button> |
|
|
</Stack> |
|
|
</Stack> |
|
|
{ |
|
|
{ |
|
|
tabIndex == 0 && |
|
|
|
|
|
|
|
|
// tabIndex == 0 && |
|
|
<SearchBox |
|
|
<SearchBox |
|
|
criteria={searchCriteria} |
|
|
criteria={searchCriteria} |
|
|
onSearch={(query) => { |
|
|
onSearch={(query) => { |
|
|
console.log(query) |
|
|
console.log(query) |
|
|
setFilteredIssuedInvoices( |
|
|
|
|
|
issuedInvoice.filter( |
|
|
|
|
|
|
|
|
setFilterInovices( |
|
|
|
|
|
invoices.filter( |
|
|
(s) => |
|
|
(s) => |
|
|
(isDateInRange(s.invoiceDate, query.invoiceDate ?? undefined, query.invoiceDateTo ?? undefined)) && |
|
|
|
|
|
(isDateInRange(s.dueDate, query.dueDate ?? undefined, query.dueDateTo ?? undefined)) && |
|
|
|
|
|
|
|
|
(isDateInRange(s.issuedDate, query.invoiceDate ?? undefined, query.invoiceDateTo ?? undefined)) && |
|
|
|
|
|
(isDateInRange(s.receiptDate, query.dueDate ?? undefined, query.dueDateTo ?? undefined)) && |
|
|
(s.invoiceNo.toLowerCase().includes(query.invoiceNo.toLowerCase())) && |
|
|
(s.invoiceNo.toLowerCase().includes(query.invoiceNo.toLowerCase())) && |
|
|
(s.projectCode.toLowerCase().includes(query.projectCode.toLowerCase())) |
|
|
|
|
|
|
|
|
(s.projectCode.toLowerCase().includes(query.projectCode.toLowerCase())) && |
|
|
|
|
|
(s.team.toLowerCase().includes(query.team.toLowerCase())) |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
}} |
|
|
}} |
|
|
onReset={onReset} |
|
|
onReset={onReset} |
|
|
/> |
|
|
/> |
|
|
} |
|
|
} |
|
|
{ |
|
|
|
|
|
|
|
|
{/* { |
|
|
tabIndex == 1 && |
|
|
tabIndex == 1 && |
|
|
<SearchBox |
|
|
<SearchBox |
|
|
criteria={searchCriteria2} |
|
|
criteria={searchCriteria2} |
|
@@ -312,25 +341,25 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice }) => { |
|
|
}} |
|
|
}} |
|
|
onReset={onReset} |
|
|
onReset={onReset} |
|
|
/> |
|
|
/> |
|
|
} |
|
|
|
|
|
<Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> |
|
|
|
|
|
|
|
|
} */} |
|
|
|
|
|
{/* {<Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> |
|
|
<Tab label={t("Issued Invoices")}/> |
|
|
<Tab label={t("Issued Invoices")}/> |
|
|
<Tab label={t("Received Invoices")}/> |
|
|
<Tab label={t("Received Invoices")}/> |
|
|
</Tabs> |
|
|
|
|
|
|
|
|
</Tabs>} */} |
|
|
{ |
|
|
{ |
|
|
tabIndex == 0 && |
|
|
|
|
|
<SearchResults<issuedInvoiceList> |
|
|
|
|
|
items={filteredIssuedInvoices} |
|
|
|
|
|
columns={columns} |
|
|
|
|
|
|
|
|
// tabIndex == 0 && |
|
|
|
|
|
<SearchResults<invoiceList> |
|
|
|
|
|
items={filteredIvoices} |
|
|
|
|
|
columns={combinedColumns} |
|
|
/> |
|
|
/> |
|
|
} |
|
|
} |
|
|
{ |
|
|
|
|
|
|
|
|
{/* { |
|
|
tabIndex == 1 && |
|
|
tabIndex == 1 && |
|
|
<SearchResults<receivedInvoiceList> |
|
|
<SearchResults<receivedInvoiceList> |
|
|
items={filteredReceivedInvoices} |
|
|
items={filteredReceivedInvoices} |
|
|
columns={columns2} |
|
|
columns={columns2} |
|
|
/> |
|
|
/> |
|
|
} |
|
|
|
|
|
|
|
|
} */} |
|
|
|
|
|
|
|
|
</> |
|
|
</> |
|
|
); |
|
|
); |
|
|