|
@@ -21,6 +21,7 @@ import { uniq } from "lodash"; |
|
|
import CreateInvoiceModal from "./CreateInvoiceModal"; |
|
|
import CreateInvoiceModal from "./CreateInvoiceModal"; |
|
|
import { ProjectResult } from "@/app/api/projects"; |
|
|
import { ProjectResult } from "@/app/api/projects"; |
|
|
import { IMPORT_INVOICE, IMPORT_RECEIPT } from "@/middleware"; |
|
|
import { IMPORT_INVOICE, IMPORT_RECEIPT } from "@/middleware"; |
|
|
|
|
|
import InvoiceSearchLoading from "./InvoiceSearchLoading"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -41,13 +42,17 @@ type invoiceListRow = Partial< |
|
|
} |
|
|
} |
|
|
>; |
|
|
>; |
|
|
|
|
|
|
|
|
|
|
|
interface SubComponents { |
|
|
|
|
|
Loading: typeof InvoiceSearchLoading; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
type SearchQuery = Partial<Omit<issuedInvoiceSearchForm, "id">>; |
|
|
type SearchQuery = Partial<Omit<issuedInvoiceSearchForm, "id">>; |
|
|
type SearchParamNames = keyof SearchQuery; |
|
|
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> = ({ invoices, projects, abilities }) => { |
|
|
|
|
|
|
|
|
const InvoiceSearch: React.FC<Props> & SubComponents = ({ invoices, projects, abilities }) => { |
|
|
console.log(abilities) |
|
|
console.log(abilities) |
|
|
const { t } = useTranslation("Invoice"); |
|
|
const { t } = useTranslation("Invoice"); |
|
|
|
|
|
|
|
@@ -96,18 +101,22 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setLoading(true) |
|
|
const formData = new FormData(); |
|
|
const formData = new FormData(); |
|
|
formData.append('multipartFileList', file); |
|
|
formData.append('multipartFileList', file); |
|
|
|
|
|
|
|
|
const response = await importIssuedInovice(formData); |
|
|
const response = await importIssuedInovice(formData); |
|
|
|
|
|
|
|
|
// response: status, message, projectList, emptyRowList, invoiceList |
|
|
// response: status, message, projectList, emptyRowList, invoiceList |
|
|
|
|
|
|
|
|
if (response.status) { |
|
|
if (response.status) { |
|
|
successDialog(t("Import Success"), t).then(() => { |
|
|
successDialog(t("Import Success"), t).then(() => { |
|
|
|
|
|
setLoading(false) |
|
|
window.location.reload(); |
|
|
window.location.reload(); |
|
|
}); |
|
|
}); |
|
|
} else { |
|
|
} else { |
|
|
handleImportError(response); |
|
|
handleImportError(response); |
|
|
|
|
|
setLoading(false) |
|
|
} |
|
|
} |
|
|
} catch (err) { |
|
|
} catch (err) { |
|
|
console.log(err); |
|
|
console.log(err); |
|
@@ -177,6 +186,7 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
|
|
|
|
|
|
const formData = new FormData(); |
|
|
const formData = new FormData(); |
|
|
formData.append('multipartFileList', file); |
|
|
formData.append('multipartFileList', file); |
|
|
|
|
|
setLoading(true) |
|
|
|
|
|
|
|
|
const response = await importReceivedInovice(formData) |
|
|
const response = await importReceivedInovice(formData) |
|
|
console.log(response) |
|
|
console.log(response) |
|
@@ -185,6 +195,7 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
successDialog(t("Import Success"), t).then(() => { |
|
|
successDialog(t("Import Success"), t).then(() => { |
|
|
window.location.reload() |
|
|
window.location.reload() |
|
|
}) |
|
|
}) |
|
|
|
|
|
setLoading(false) |
|
|
}else{ |
|
|
}else{ |
|
|
if (response.emptyRowList.length >= 1){ |
|
|
if (response.emptyRowList.length >= 1){ |
|
|
errorDialogWithContent(t("Import Fail"), |
|
|
errorDialogWithContent(t("Import Fail"), |
|
@@ -220,6 +231,7 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
window.location.reload() |
|
|
window.location.reload() |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
setLoading(false) |
|
|
} |
|
|
} |
|
|
}catch(error){ |
|
|
}catch(error){ |
|
|
console.log(error) |
|
|
console.log(error) |
|
@@ -423,10 +435,14 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
return importRight |
|
|
return importRight |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const [loading, setLoading] = React.useState(false); |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<> |
|
|
<> |
|
|
|
|
|
|
|
|
|
|
|
{loading && <InvoiceSearch.Loading />} |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
!loading && |
|
|
isAddInvoiceRightExist() && |
|
|
isAddInvoiceRightExist() && |
|
|
<Stack |
|
|
<Stack |
|
|
direction="row" |
|
|
direction="row" |
|
@@ -468,6 +484,7 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
!loading && |
|
|
// tabIndex == 0 && |
|
|
// tabIndex == 0 && |
|
|
<SearchBox |
|
|
<SearchBox |
|
|
criteria={searchCriteria} |
|
|
criteria={searchCriteria} |
|
@@ -486,23 +503,31 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
onReset={onReset} |
|
|
onReset={onReset} |
|
|
/> |
|
|
/> |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
!loading && |
|
|
|
|
|
<> |
|
|
|
|
|
<Divider sx={{ paddingBlockStart: 2 }} /> |
|
|
|
|
|
<Card sx={{ display: "block" }}> |
|
|
|
|
|
<CardContent> |
|
|
|
|
|
<Stack direction="row" justifyContent="space-between"> |
|
|
|
|
|
<Typography variant="h6">{t('Total Issued Amount (HKD)')}:</Typography> |
|
|
|
|
|
<Typography variant="h6">{moneyFormatter.format(filteredIvoices.reduce((acc, current) => (acc + current.issuedAmount), 0))}</Typography> |
|
|
|
|
|
</Stack> |
|
|
|
|
|
<Stack direction="row" justifyContent="space-between"> |
|
|
|
|
|
<Typography variant="h6">{t('Total Received Amount (HKD)')}:</Typography> |
|
|
|
|
|
<Typography variant="h6">{moneyFormatter.format(filteredIvoices.reduce((acc, current) => (acc + current.receivedAmount), 0))}</Typography> |
|
|
|
|
|
</Stack> |
|
|
|
|
|
</CardContent> |
|
|
|
|
|
</Card> |
|
|
|
|
|
<Divider sx={{ paddingBlockEnd: 2 }} /> |
|
|
|
|
|
</> |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<Divider sx={{ paddingBlockStart: 2 }} /> |
|
|
|
|
|
<Card sx={{ display: "block" }}> |
|
|
|
|
|
<CardContent> |
|
|
|
|
|
<Stack direction="row" justifyContent="space-between"> |
|
|
|
|
|
<Typography variant="h6">{t('Total Issued Amount (HKD)')}:</Typography> |
|
|
|
|
|
<Typography variant="h6">{moneyFormatter.format(filteredIvoices.reduce((acc, current) => (acc + current.issuedAmount), 0))}</Typography> |
|
|
|
|
|
</Stack> |
|
|
|
|
|
<Stack direction="row" justifyContent="space-between"> |
|
|
|
|
|
<Typography variant="h6">{t('Total Received Amount (HKD)')}:</Typography> |
|
|
|
|
|
<Typography variant="h6">{moneyFormatter.format(filteredIvoices.reduce((acc, current) => (acc + current.receivedAmount), 0))}</Typography> |
|
|
|
|
|
</Stack> |
|
|
|
|
|
</CardContent> |
|
|
|
|
|
</Card> |
|
|
|
|
|
<Divider sx={{ paddingBlockEnd: 2 }} /> |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
!loading && |
|
|
// tabIndex == 0 && |
|
|
// tabIndex == 0 && |
|
|
<SearchResults<invoiceList> |
|
|
<SearchResults<invoiceList> |
|
|
items={filteredIvoices} |
|
|
items={filteredIvoices} |
|
@@ -586,4 +611,6 @@ const InvoiceSearch: React.FC<Props> = ({ invoices, projects, abilities }) => { |
|
|
); |
|
|
); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
InvoiceSearch.Loading = InvoiceSearchLoading; |
|
|
|
|
|
|
|
|
export default InvoiceSearch; |
|
|
export default InvoiceSearch; |