Adding api for Finance for Export.

This commit is contained in:
Kartik Sharma 2025-12-03 09:53:41 +05:30
parent 03fb5f7bc3
commit 917e7f3ccc
6 changed files with 303 additions and 152 deletions

View File

@ -1,61 +1,84 @@
import ExpenseRepository from "../../repositories/ExpsenseRepository";
import moment from "moment"; import moment from "moment";
import { exportToCSV, exportToExcel, exportToPDF, printTable } from "../../utils/tableExportUtils"; import { exportToCSV, exportToExcel, exportToPDF, printTable } from "../../utils/tableExportUtils";
import showToast from "../../services/toastService";
/** const handleExpenseExport = async (
* Handles exporting expenses data to CSV, Excel, PDF, or Print type,
* @param {"csv"|"excel"|"pdf"|"print"} type filters = {},
* @param {Array} expenses - List of expenses searchString = "",
* @param {React.RefObject} tableRef - Table reference for printing tableRef = null,
*/ setLoading = null
const handleExpenseExport = (type, expenses, tableRef) => { ) => {
if (!expenses || expenses.length === 0) return; try {
if (setLoading) setLoading(true);
// Map export data const safeSearchString = typeof searchString === "string" ? searchString : "";
const exportData = expenses.map((item) => ({ let allExpenses = [];
"Expense ID": item?.expenseUId ?? "-", let pageNumber = 1;
"Expense Category": item?.expenseCategory?.name ?? "-", const pageSize = 1000; // fetch 1000 per API call
"Payment Mode": item?.paymentMode?.name ?? "-", let hasMore = true;
"Submitted By": `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim() || "-",
"Submitted": item?.createdAt ? moment(item.createdAt).format("DD-MMM-YYYY") : "-",
"Amount": item?.amount?.toLocaleString() ?? "-",
"Currency": item?.currency?.currencyCode ?? "-",
"Status": item?.status?.name ?? "-",
"Project": item?.project?.name ?? "-",
}));
// Define column order while (hasMore) {
const columns = [ const response = await ExpenseRepository.GetExpenseList(
"Expense ID", pageSize,
"Expense Category", pageNumber,
"Payment Mode", filters,
"Submitted By", safeSearchString
"Submitted", );
"Amount",
"Currency",
"Status",
"Project",
];
switch (type) { const currentPageData = response?.data?.data || [];
case "csv": allExpenses = allExpenses.concat(currentPageData);
exportToCSV(exportData, "expenses", columns);
break;
case "excel": // If returned data length is less than pageSize, we reached the last page
exportToExcel(exportData, "expenses", columns); if (currentPageData.length < pageSize) {
break; hasMore = false;
} else {
pageNumber += 1; // fetch next page
}
}
case "pdf": if (!allExpenses.length) {
exportToPDF(exportData, "expenses", columns); showToast("No expenses found!", "warning");
break; return;
}
case "print": // Map export data
if (tableRef?.current) printTable(tableRef.current); const exportData = allExpenses.map((item) => ({
break; "Expense ID": item?.expenseUId ?? "-",
"Expense Category": item?.expenseCategory?.name ?? "-",
"Payment Mode": item?.paymentMode?.name ?? "-",
"Submitted By": `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim() || "-",
"Submitted": item?.createdAt ? moment(item.createdAt).format("DD-MMM-YYYY") : "-",
"Amount": item?.amount != null
? `${item.amount.toLocaleString()} ${item.currency?.currencyCode ?? ""}`
: "-",
"Status": item?.status?.name ?? "-",
}));
default:
console.warn("Unhandled export type:", type); switch (type) {
break; case "csv":
exportToCSV(exportData, "Expenses");
break;
case "excel":
exportToExcel(exportData, "Expenses");
break;
case "pdf":
exportToPDF(exportData, "Expenses");
break;
case "print":
if (tableRef?.current) printTable(tableRef.current);
break;
default:
console.warn("Unknown export type:", type);
}
} catch (err) {
console.error(err);
showToast("Failed to export expenses", "error");
} finally {
if (setLoading) setLoading(false);
} }
}; };

View File

@ -1,58 +1,84 @@
import moment from "moment"; import moment from "moment";
import { exportToCSV, exportToExcel, exportToPDF, printTable } from "../../utils/tableExportUtils"; import { exportToCSV, exportToExcel, exportToPDF, printTable } from "../../utils/tableExportUtils";
import ExpenseRepository from "../../repositories/ExpsenseRepository";
const handlePaymentRequestExport = (type, requests, tableRef) => { const handlePaymentRequestExport = async (
if (!requests || requests.length === 0) return; type,
filters = {},
searchString = "",
tableRef = null,
setLoading = null
) => {
try {
if (setLoading) setLoading(true);
// Map export data const safeSearchString = typeof searchString === "string" ? searchString : "";
const exportData = requests.map((item) => ({ let allPaymentRequest = [];
"Request ID": item?.paymentRequestUID ?? "-", let pageNumber = 1;
"Title": item?.title ?? "-", const pageSize = 1000;
"Payee": item?.payee ?? "-", let hasMore = true;
"Amount": item?.amount?.toLocaleString() ?? "-",
"Currency": item?.currency?.currencyCode ?? "-",
"Created At": item?.createdAt ? moment(item.createdAt).format("DD-MMM-YYYY") : "-",
"Due Date": item?.dueDate ? moment(item.dueDate).format("DD-MMM-YYYY") : "-",
"Status": item?.expenseStatus?.name ?? "-",
"Submitted By": `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim() || "-",
"Project": item?.project?.name ?? "-",
}));
// Define column order while (hasMore) {
const columns = [ const response = await ExpenseRepository.GetPaymentRequestList(
"Request ID", pageSize,
"Title", pageNumber,
"Payee", filters,
"Amount", true, // isActive
"Currency", safeSearchString
"Created At", );
"Due Date",
"Status",
"Submitted By",
"Project",
];
switch (type) { const currentPageData = response?.data?.data || [];
case "csv": allPaymentRequest = allPaymentRequest.concat(currentPageData);
exportToCSV(exportData, "payment-requests", columns);
break;
case "excel": if (currentPageData.length < pageSize) {
exportToExcel(exportData, "payment-requests", columns); hasMore = false;
break; } else {
pageNumber += 1;
}
}
case "pdf": if (!allPaymentRequest.length) {
exportToPDF(exportData, "payment-requests", columns); console.warn("No payment requests found!");
break; return;
}
case "print": const exportData = allPaymentRequest.map((item) => ({
if (tableRef?.current) printTable(tableRef.current); "Request ID": item?.paymentRequestUID ?? "-",
break; "Title": item?.title ?? "-",
"Payee": item?.payee ?? "-",
"Amount": item?.amount != null ? Number(item.amount).toLocaleString() : "-",
"Currency": item?.currency?.currencyCode ?? "-",
"Created At": item?.createdAt ? moment(item.createdAt).format("DD-MMM-YYYY") : "-",
"Due Date": item?.dueDate ? moment(item.dueDate).format("DD-MMM-YYYY") : "-",
"Status": item?.expenseStatus?.name ?? "-",
"Submitted By": `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim() || "-",
"Project": item?.project?.name ?? "-",
}));
default: switch (type) {
console.warn("Unhandled export type:", type); case "csv":
break; exportToCSV(exportData, "PaymentRequests");
break;
case "excel":
exportToExcel(exportData, "PaymentRequests");
break;
case "pdf":
exportToPDF(exportData, "PaymentRequests");
break;
case "print":
if (tableRef?.current) printTable(tableRef.current);
break;
default:
console.warn("Unknown export type:", type);
}
} catch (err) {
console.error("Export failed:", err);
} finally {
if (setLoading) setLoading(false);
} }
}; };
export default handlePaymentRequestExport; export default handlePaymentRequestExport;

View File

@ -1,63 +1,160 @@
import moment from "moment"; import moment from "moment";
import { exportToCSV,exportToExcel,exportToPDF,printTable } from "../../utils/tableExportUtils"; import { exportToCSV, exportToExcel, exportToPDF, printTable } from "../../utils/tableExportUtils";
import { FREQUENCY_FOR_RECURRING } from "../../utils/constants"; import { FREQUENCY_FOR_RECURRING } from "../../utils/constants";
import ExpenseRepository from "../../repositories/ExpsenseRepository";
const handleRecurringExpenseExport = (type, expenses, tableRef) => { // const handleRecurringExpenseExport = (type, expenses, tableRef) => {
if (!expenses || expenses.length === 0) return; // if (!expenses || expenses.length === 0) return;
// Mapped Export Data // // Mapped Export Data
const exportData = expenses.map((item) => ({ // const exportData = expenses.map((item) => ({
Category: item?.expenseCategory?.name ?? "-", // Category: item?.expenseCategory?.name ?? "-",
Title: item?.title ?? "-", // Title: item?.title ?? "-",
Payee: item?.payee ?? "-", // Payee: item?.payee ?? "-",
Frequency: // Frequency:
item?.frequency !== undefined && item?.frequency !== null // item?.frequency !== undefined && item?.frequency !== null
? FREQUENCY_FOR_RECURRING[item?.frequency] ?? "-" // ? FREQUENCY_FOR_RECURRING[item?.frequency] ?? "-"
// : "-",
// Amount: item?.amount ? item.amount.toLocaleString() : "-",
// Currency: item?.currency?.symbol ?? "-",
// "Next Generation Date": item?.nextGenerationDate
// ? moment(item.nextGenerationDate).format("DD-MMM-YYYY")
// : "-",
// Status: item?.status?.name ?? "-",
// "Created At": item?.createdAt
// ? moment(item.createdAt).format("DD-MMM-YYYY")
// : "-",
// }));
// // COLUMN ORDER
// const columns = [
// "Category",
// "Title",
// "Payee",
// "Frequency",
// "Amount",
// "Currency",
// "Next Generation Date",
// "Status",
// "Created At",
// ];
// switch (type) {
// case "csv":
// exportToCSV(exportData, "recurring-expense", columns);
// break;
// case "excel":
// exportToExcel(exportData, "recurring-expense", columns);
// break;
// case "pdf":
// exportToPDF(exportData, "recurring-expense", columns);
// break;
// case "print":
// if (tableRef?.current) printTable(tableRef.current);
// break;
// default:
// console.warn("Unhandled export type:", type);
// break;
// }
// };
const handleRecurringExpenseExport = async (
type,
filters = {},
searchString = "",
tableRef = null,
setLoading = null
) => {
try {
if (setLoading) setLoading(true);
const safeSearchString = typeof searchString === "string" ? searchString : "";
let allRecurringExpense = [];
let pageNumber = 1;
const pageSize = 1000;
let hasMore = true;
while (hasMore) {
const response = await ExpenseRepository.GetRecurringExpenseList(
pageSize,
pageNumber,
filters,
true, // isActive
safeSearchString
);
const currentPageData = response?.data?.data || [];
allRecurringExpense = allRecurringExpense.concat(currentPageData);
if (currentPageData.length < pageSize) {
hasMore = false;
} else {
pageNumber += 1;
}
}
if (!allRecurringExpense.length) {
console.warn("No payment requests found!");
return;
}
const exportData = allRecurringExpense.map((item) => ({
Category: item?.expenseCategory?.name ?? "-",
Title: item?.title ?? "-",
Payee: item?.payee ?? "-",
Frequency:
item?.frequency !== undefined && item?.frequency !== null
? FREQUENCY_FOR_RECURRING[item?.frequency] ?? "-"
: "-",
Amount: item?.amount ? item.amount.toLocaleString() : "-",
Currency: item?.currency?.symbol ?? "-",
"Next Generation Date": item?.nextGenerationDate
? moment(item.nextGenerationDate).format("DD-MMM-YYYY")
: "-", : "-",
Amount: item?.amount ? item.amount.toLocaleString() : "-", Status: item?.status?.name ?? "-",
Currency: item?.currency?.symbol ?? "-", "Created At": item?.createdAt
"Next Generation Date": item?.nextGenerationDate ? moment(item.createdAt).format("DD-MMM-YYYY")
? moment(item.nextGenerationDate).format("DD-MMM-YYYY") : "-",
: "-", }));
Status: item?.status?.name ?? "-",
"Created At": item?.createdAt
? moment(item.createdAt).format("DD-MMM-YYYY")
: "-",
}));
// COLUMN ORDER // COLUMN ORDER
const columns = [ const columns = [
"Category", "Category",
"Title", "Title",
"Payee", "Payee",
"Frequency", "Frequency",
"Amount", "Amount",
"Currency", "Currency",
"Next Generation Date", "Next Generation Date",
"Status", "Status",
"Created At", "Created At",
]; ];
switch (type) { switch (type) {
case "csv": case "csv":
exportToCSV(exportData, "recurring-expense", columns); exportToCSV(exportData, "recurring-expense", columns);
break; break;
case "excel":
exportToExcel(exportData, "recurring-expense", columns);
break;
case "pdf":
exportToPDF(exportData, "recurring-expense", columns);
break;
case "print":
if (tableRef?.current) printTable(tableRef.current);
break;
default:
console.warn("Unknown export type:", type);
}
case "excel": } catch (err) {
exportToExcel(exportData, "recurring-expense", columns); console.error("Export failed:", err);
break; } finally {
if (setLoading) setLoading(false);
case "pdf":
exportToPDF(exportData, "recurring-expense", columns);
break;
case "print":
if (tableRef?.current) printTable(tableRef.current);
break;
default:
console.warn("Unhandled export type:", type);
break;
} }
}; };

View File

@ -118,9 +118,10 @@ const ExpensePage = () => {
}; };
const handleExport = (type) => { const handleExport = (type) => {
handleExpenseExport(type, filteredData, tableRef); // <-- corrected handleExpenseExport(type, filters, searchText, tableRef);
}; };
return ( return (
<ExpenseContext.Provider value={contextValue}> <ExpenseContext.Provider value={contextValue}>
<div className="container-fluid"> <div className="container-fluid">

View File

@ -26,11 +26,13 @@ const PaymentRequestPage = () => {
const [filters, setFilters] = useState(defaultPaymentRequestFilter); const [filters, setFilters] = useState(defaultPaymentRequestFilter);
const [filterData, setFilterdata] = useState(null); const [filterData, setFilterdata] = useState(null);
const [ViewDocument, setDocumentView] = useState({ IsOpen: false, Image: null }); const [ViewDocument, setDocumentView] = useState({ IsOpen: false, Image: null });
const [searchText, setSearchText] = useState("");
const [isExpenseGenerate, setIsExpenseGenerate] = useState({ IsOpen: null, RequestId: null }); const [isExpenseGenerate, setIsExpenseGenerate] = useState({ IsOpen: null, RequestId: null });
const [modalSize, setModalSize] = useState("md"); const [modalSize, setModalSize] = useState("md");
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const updatedRef = useRef(); const updatedRef = useRef();
const { setOffcanvasContent, setShowTrigger } = useFab(); const { setOffcanvasContent, setShowTrigger } = useFab();
const [exportLoading, setExportLoading] = useState(false);
const tableRef = useRef(null); const tableRef = useRef(null);
const [filteredData, setFilteredData] = useState([]); const [filteredData, setFilteredData] = useState([]);
const contextValue = { const contextValue = {
@ -78,9 +80,9 @@ const PaymentRequestPage = () => {
}); });
}; };
const handleExport = (type) => { const handleExport = (type) => {
handlePaymentRequestExport(type, filteredData, tableRef); // <-- corrected handlePaymentRequestExport(type, filters, search, tableRef, setExportLoading);
}; };
return ( return (
<PaymentRequestContext.Provider value={contextValue}> <PaymentRequestContext.Provider value={contextValue}>

View File

@ -5,7 +5,7 @@ import { useFab } from "../../Context/FabContext";
import ManageRecurringExpense from "../../components/RecurringExpense/ManageRecurringExpense"; import ManageRecurringExpense from "../../components/RecurringExpense/ManageRecurringExpense";
import RecurringExpenseList from "../../components/RecurringExpense/RecurringExpenseList"; import RecurringExpenseList from "../../components/RecurringExpense/RecurringExpenseList";
import { PAYEE_RECURRING_EXPENSE } from "../../utils/constants"; import { PAYEE_RECURRING_EXPENSE } from "../../utils/constants";
import { SearchRecurringExpenseSchema } from "../../components/RecurringExpense/RecurringExpenseSchema"; import { defaultRecurringExpense, SearchRecurringExpenseSchema } from "../../components/RecurringExpense/RecurringExpenseSchema";
import ViewRecurringExpense from "../../components/RecurringExpense/ViewRecurringExpense"; import ViewRecurringExpense from "../../components/RecurringExpense/ViewRecurringExpense";
import handleRecurringExpenseExport from "../../components/RecurringExpense/handleRecurringExpenseExport"; import handleRecurringExpenseExport from "../../components/RecurringExpense/handleRecurringExpenseExport";
@ -17,7 +17,7 @@ export const useRecurringExpenseContext = () => {
"useRecurringExpenseContext must be used within an ExpenseProvider" "useRecurringExpenseContext must be used within an ExpenseProvider"
); );
} }
return context; return context;
}; };
const RecurringExpensePage = () => { const RecurringExpensePage = () => {
const [ManageRequest, setManageRequest] = useState({ const [ManageRequest, setManageRequest] = useState({
@ -27,7 +27,9 @@ const RecurringExpensePage = () => {
const tableRef = useRef(null); const tableRef = useRef(null);
const [filteredData, setFilteredData] = useState([]); const [filteredData, setFilteredData] = useState([]);
const [exportLoading, setExportLoading] = useState(false);
const [searchText, setSearchText] = useState("");
const [filters, setFilters] = useState(defaultRecurringExpense);
const [viewRecurring, setViewRecurring] = useState({ const [viewRecurring, setViewRecurring] = useState({
view: false, view: false,
recurringId: null, recurringId: null,
@ -52,7 +54,7 @@ const RecurringExpensePage = () => {
const handleExport = (type) => { const handleExport = (type) => {
handleRecurringExpenseExport(type, filteredData, tableRef); handleRecurringExpenseExport(type, filters, search, tableRef, setExportLoading);
}; };
return ( return (