added advance payment api
This commit is contained in:
parent
9b091840d6
commit
bac9f25df1
@ -1,82 +1,31 @@
|
||||
import React from "react";
|
||||
import { useExpenseTransactions } from "../../hooks/useExpense";
|
||||
import Error from "../common/Error";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
|
||||
const AdvancePaymentList = ({ employeeId }) => {
|
||||
const {data,isError, isLoading,isFetching,error} = useExpenseTransactions(employeeId)
|
||||
const record = {
|
||||
openingBalance: 25000.0,
|
||||
rows: [
|
||||
{ id: 1, description: "Opening Balance", credit: 0.0, debit: 0.0 },
|
||||
{
|
||||
id: 2,
|
||||
description: "Sales Invoice #INV-001",
|
||||
credit: 15000.0,
|
||||
debit: 0.0,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
description: "Sales Invoice #INV-002",
|
||||
credit: 12000.0,
|
||||
debit: 0.0,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
description: "Purchase - Raw Materials",
|
||||
credit: 0.0,
|
||||
debit: 8000.0,
|
||||
},
|
||||
{ id: 5, description: "Office Rent - June", credit: 0.0, debit: 5000.0 },
|
||||
{
|
||||
id: 6,
|
||||
description: "Client Payment Received (Bank)",
|
||||
credit: 10000.0,
|
||||
debit: 0.0,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
description: "Supplier Payment - ABC Corp",
|
||||
credit: 0.0,
|
||||
debit: 6000.0,
|
||||
},
|
||||
{ id: 8, description: "Interest Income", credit: 750.0, debit: 0.0 },
|
||||
{ id: 9, description: "Bank Charges", credit: 0.0, debit: 250.0 },
|
||||
{
|
||||
id: 10,
|
||||
description: "Utilities - Electricity",
|
||||
credit: 0.0,
|
||||
debit: 1800.0,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
description: "Service Income - Project Alpha",
|
||||
credit: 5000.0,
|
||||
debit: 0.0,
|
||||
},
|
||||
{ id: 12, description: "Misc Expense", credit: 0.0, debit: 450.0 },
|
||||
{
|
||||
id: 13,
|
||||
description: "Adjustment - Prior Year",
|
||||
credit: 0.0,
|
||||
debit: 500.0,
|
||||
},
|
||||
{ id: 14, description: "Commission Earned", credit: 1200.0, debit: 0.0 },
|
||||
{
|
||||
id: 15,
|
||||
description: "Employee Salary - June",
|
||||
credit: 0.0,
|
||||
debit: 9500.0,
|
||||
},
|
||||
{ id: 16, description: "GST Refund", credit: 2000.0, debit: 0.0 },
|
||||
{ id: 17, description: "Insurance Premium", credit: 0.0, debit: 3000.0 },
|
||||
{ id: 18, description: "Late Fee Collected", credit: 350.0, debit: 0.0 },
|
||||
{ id: 19, description: "Maintenance Expense", credit: 0.0, debit: 600.0 },
|
||||
{ id: 20, description: "Closing Balance", credit: 0.0, debit: 0.0 },
|
||||
],
|
||||
};
|
||||
let currentBalance = record.openingBalance;
|
||||
const rowsWithBalance = record.rows.map((r) => {
|
||||
currentBalance += r.credit - r.debit;
|
||||
return { ...r, balance: currentBalance };
|
||||
const { data, isError, isLoading, error } =
|
||||
useExpenseTransactions(employeeId);
|
||||
|
||||
const records = data?.json || [];
|
||||
|
||||
let currentBalance = 0;
|
||||
|
||||
const rowsWithBalance = data?.map((r) => {
|
||||
const isCredit = r.amount > 0;
|
||||
const credit = isCredit ? r.amount : 0;
|
||||
const debit = !isCredit ? Math.abs(r.amount) : 0;
|
||||
currentBalance += credit - debit;
|
||||
|
||||
return {
|
||||
id: r.id,
|
||||
description: r.title,
|
||||
projectName: r.project?.name,
|
||||
createdAt: r.createdAt,
|
||||
credit,
|
||||
debit,
|
||||
balance: currentBalance,
|
||||
};
|
||||
});
|
||||
|
||||
const columns = [
|
||||
@ -110,10 +59,16 @@ const AdvancePaymentList = ({ employeeId }) => {
|
||||
},
|
||||
];
|
||||
|
||||
if (isLoading) return <div>Loading...</div>;
|
||||
if (isError){
|
||||
return <div>{error.status === 404 ? "No advance payment transactions found." : <Error error={error}/>}</div>
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="table-responsive ">
|
||||
<table className="table align-middle">
|
||||
<thead className="table_header_border ">
|
||||
<div className="row ">
|
||||
<div className="table-responsive">
|
||||
{employeeId ? ( <table className="table align-middle">
|
||||
<thead className="table_header_border">
|
||||
<tr>
|
||||
{columns.map((col) => (
|
||||
<th key={col.key} className={col.align}>
|
||||
@ -123,28 +78,32 @@ const AdvancePaymentList = ({ employeeId }) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rowsWithBalance.map((row) => (
|
||||
{rowsWithBalance?.map((row) => (
|
||||
<tr key={row.id}>
|
||||
{columns.map((col) => (
|
||||
<td key={col.key} className={`${col.align} p-6`}>
|
||||
{col.key === "balance" ||
|
||||
col.key === "credit" ||
|
||||
col.key === "debit"
|
||||
? row[col.key].toLocaleString("en-IN", {
|
||||
style: "currency",
|
||||
currency: "INR",
|
||||
})
|
||||
: (<div className="d-flex flex-column">
|
||||
<small>{new Date().toISOString()}</small>
|
||||
<small>Projec Name</small>
|
||||
<small>{row[col.key]}</small>
|
||||
</div>)}
|
||||
<td key={col.key} className={`${col.align} p-2`}>
|
||||
{["balance", "credit", "debit"].includes(col.key) ? (
|
||||
row[col.key].toLocaleString("en-IN", {
|
||||
style: "currency",
|
||||
currency: "INR",
|
||||
})
|
||||
) : (
|
||||
<div className="d-flex flex-column text-start ">
|
||||
<small className="text-muted">
|
||||
{formatUTCToLocalTime(row.createdAt)}
|
||||
</small>
|
||||
<small className="fw-semibold text-dark">
|
||||
{row.projectName}
|
||||
</small>
|
||||
<small>{row.description}</small>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
<tfoot className="table-secondary fw-bold ">
|
||||
<tfoot className="table-secondary fw-bold">
|
||||
<tr>
|
||||
<td className="text-start p-3">Final Balance</td>
|
||||
<td className="text-end" colSpan="3">
|
||||
@ -155,7 +114,12 @@ const AdvancePaymentList = ({ employeeId }) => {
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</table>):(
|
||||
<div className="d-flex justify-content-center align-items-center" style={{ height: "200px" }}>
|
||||
<p className="text-muted m-0">Please Select Employee</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -167,9 +167,9 @@ export const defaultActionValues = {
|
||||
reimburseTransactionId: null,
|
||||
reimburseDate: null,
|
||||
reimburseById: null,
|
||||
tdsPercentage: null,
|
||||
tdsPercentage: 0,
|
||||
baseAmount:null,
|
||||
taxAmount: null,
|
||||
taxAmount: 0,
|
||||
};
|
||||
|
||||
export const SearchSchema = z.object({
|
||||
|
||||
@ -93,6 +93,9 @@ export const PaymentRequestActionScheam = (
|
||||
paidTransactionId: z.string().nullable().optional(),
|
||||
paidAt: z.string().nullable().optional(),
|
||||
paidById: z.string().nullable().optional(),
|
||||
tdsPercentage: z.string().nullable().optional(),
|
||||
baseAmount: z.string().nullable().optional(),
|
||||
taxAmount: z.string().nullable().optional(),
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (isTransaction) {
|
||||
@ -110,7 +113,7 @@ export const PaymentRequestActionScheam = (
|
||||
message: "Transacion Date is required",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (!data.paidById) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
@ -118,6 +121,20 @@ export const PaymentRequestActionScheam = (
|
||||
message: "Paid By is required",
|
||||
});
|
||||
}
|
||||
if (!data.baseAmount) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["baseAmount"],
|
||||
message: "Base Amount i required",
|
||||
});
|
||||
}
|
||||
if (!data.taxAmount) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["taxAmount"],
|
||||
message: "Tax is required",
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -128,40 +145,38 @@ export const defaultPaymentRequestActionValues = {
|
||||
paidTransactionId: null,
|
||||
paidAt: null,
|
||||
paidById: null,
|
||||
tdsPercentage:"0",
|
||||
baseAmount: null,
|
||||
taxAmount:null,
|
||||
};
|
||||
|
||||
|
||||
export const RequestedExpenseSchema =
|
||||
|
||||
z.object({
|
||||
paymentModeId: z.string().min(1, { message: "Payment mode is required" }),
|
||||
location: z.string().min(1, { message: "Location is required" }),
|
||||
gstNumber: z.string().optional(),
|
||||
billAttachments: z
|
||||
.array(
|
||||
z.object({
|
||||
fileName: z.string().min(1, { message: "Filename is required" }),
|
||||
base64Data: z.string().nullable(),
|
||||
contentType: z
|
||||
.string()
|
||||
.refine((val) => ALLOWED_TYPES.includes(val), {
|
||||
message: "Only PDF, PNG, JPG, or JPEG files are allowed",
|
||||
}),
|
||||
documentId: z.string().optional(),
|
||||
fileSize: z.number().max(MAX_FILE_SIZE, {
|
||||
message: "File size must be less than or equal to 5MB",
|
||||
}),
|
||||
description: z.string().optional(),
|
||||
isActive: z.boolean().default(true),
|
||||
})
|
||||
)
|
||||
.nonempty({ message: "At least one file attachment is required" }),
|
||||
})
|
||||
export const RequestedExpenseSchema = z.object({
|
||||
paymentModeId: z.string().min(1, { message: "Payment mode is required" }),
|
||||
location: z.string().min(1, { message: "Location is required" }),
|
||||
gstNumber: z.string().optional(),
|
||||
billAttachments: z
|
||||
.array(
|
||||
z.object({
|
||||
fileName: z.string().min(1, { message: "Filename is required" }),
|
||||
base64Data: z.string().nullable(),
|
||||
contentType: z.string().refine((val) => ALLOWED_TYPES.includes(val), {
|
||||
message: "Only PDF, PNG, JPG, or JPEG files are allowed",
|
||||
}),
|
||||
documentId: z.string().optional(),
|
||||
fileSize: z.number().max(MAX_FILE_SIZE, {
|
||||
message: "File size must be less than or equal to 5MB",
|
||||
}),
|
||||
description: z.string().optional(),
|
||||
isActive: z.boolean().default(true),
|
||||
})
|
||||
)
|
||||
.nonempty({ message: "At least one file attachment is required" }),
|
||||
});
|
||||
|
||||
export const DefaultRequestedExpense = {
|
||||
paymentModeId:"",
|
||||
location:"",
|
||||
gstNumber:"",
|
||||
paymentModeId: "",
|
||||
location: "",
|
||||
gstNumber: "",
|
||||
// amount:"",
|
||||
billAttachments:[]
|
||||
}
|
||||
billAttachments: [],
|
||||
};
|
||||
|
||||
@ -20,7 +20,6 @@ const PaymentStatusLogs = ({ data }) => {
|
||||
);
|
||||
|
||||
const timelineData = useMemo(() => {
|
||||
console.log(logsToShow)
|
||||
return logsToShow.map((log, index) => ({
|
||||
id: index + 1,
|
||||
title: log.nextStatus?.name || "Status Updated",
|
||||
|
||||
@ -50,7 +50,8 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
|
||||
const IsReview = useHasUserPermission(REVIEW_EXPENSE);
|
||||
const [imageLoaded, setImageLoaded] = useState({});
|
||||
const { setDocumentView, setModalSize,setVieRequest ,setIsExpenseGenerate} = usePaymentRequestContext();
|
||||
const { setDocumentView, setModalSize, setVieRequest, setIsExpenseGenerate } =
|
||||
usePaymentRequestContext();
|
||||
const ActionSchema =
|
||||
PaymentRequestActionScheam(IsPaymentProcess, data?.createdAt) ??
|
||||
z.object({});
|
||||
@ -118,14 +119,15 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
const handleImageLoad = (id) => {
|
||||
setImageLoaded((prev) => ({ ...prev, [id]: true }));
|
||||
};
|
||||
const handleExpense = ()=>{
|
||||
|
||||
setIsExpenseGenerate({IsOpen:true,requestId:requestId})
|
||||
setVieRequest({IsOpen:true,requestId:requestId})
|
||||
}
|
||||
|
||||
const handleExpense = () => {
|
||||
setIsExpenseGenerate({ IsOpen: true, requestId: requestId });
|
||||
setVieRequest({ IsOpen: true, requestId: requestId });
|
||||
};
|
||||
return (
|
||||
<form className="container px-3 py-2 py-md-0" onSubmit={handleSubmit(onSubmit)}>
|
||||
<form
|
||||
className="container px-3 py-2 py-md-0"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
<div className="col-12 mb-2 text-center ">
|
||||
<h5 className="fw-semibold m-0">Payment Request Details</h5>
|
||||
</div>
|
||||
@ -201,7 +203,10 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
Amount :
|
||||
</label>
|
||||
<div className="text-muted">
|
||||
{formatFigure(data?.amount,{type:"currency",currency : data?.currency?.currencyCode})}
|
||||
{formatFigure(data?.amount, {
|
||||
type: "currency",
|
||||
currency: data?.currency?.currencyCode,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -312,10 +317,14 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
</label>
|
||||
|
||||
<div className="d-flex flex-wrap gap-2">
|
||||
|
||||
{data?.attachments?.length > 0 ? (
|
||||
<FilelistView files={data?.attachments} viewFile={setDocumentView}/>
|
||||
):(<p className="m-0 text-secondary">No Attachment</p>)}
|
||||
{data?.attachments?.length > 0 ? (
|
||||
<FilelistView
|
||||
files={data?.attachments}
|
||||
viewFile={setDocumentView}
|
||||
/>
|
||||
) : (
|
||||
<p className="m-0 text-secondary">No Attachment</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -372,7 +381,7 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-12 col-md-6 text-start">
|
||||
<div className="col-12 col-md-6 text-start mb-1">
|
||||
<label className="form-label">Transaction Date </label>
|
||||
<DatePicker
|
||||
name="paidAt"
|
||||
@ -394,6 +403,49 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
projectId={null}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12 col-md-6 text-start mb-1">
|
||||
<Label className="form-label">TDS Percentage</Label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control form-control-sm"
|
||||
{...register("tdsPercentage")}
|
||||
/>
|
||||
{errors.tdsPercentage && (
|
||||
<small className="danger-text">
|
||||
{errors.tdsPercentage.message}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-12 col-md-6 text-start mb-1">
|
||||
<Label className="form-label" required>
|
||||
Base Amount
|
||||
</Label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control form-control-sm"
|
||||
{...register("baseAmount")}
|
||||
/>
|
||||
{errors.baseAmount && (
|
||||
<small className="danger-text">
|
||||
{errors.baseAmount.message}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-12 col-md-6 text-start mb-1">
|
||||
<Label className="form-label" required>
|
||||
Tax Amount
|
||||
</Label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control form-control-sm"
|
||||
{...register("taxAmount")}
|
||||
/>
|
||||
{errors.taxAmount && (
|
||||
<small className="danger-text">
|
||||
{errors.taxAmount.message}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="col-12 mb-3 text-start">
|
||||
@ -441,10 +493,18 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
): !data?.isExpenseCreated ? (<div className="text-end flex-wrap gap-2 my-2 mt-3">
|
||||
<button className="btn btn-sm btn-primary" onClick={handleExpense}>Make Expense</button>
|
||||
</div>):(<></>)}
|
||||
|
||||
) : !data?.isExpenseCreated ? (
|
||||
<div className="text-end flex-wrap gap-2 my-2 mt-3">
|
||||
<button
|
||||
className="btn btn-sm btn-primary"
|
||||
onClick={handleExpense}
|
||||
>
|
||||
Make Expense
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className=" col-sm-12 my-md-0 border-top border-md-none col-md-5">
|
||||
|
||||
@ -436,7 +436,6 @@ export const useExpenseTransactions = (employeeId)=>{
|
||||
return useQuery({
|
||||
queryKey:["transaction",employeeId],
|
||||
queryFn:async()=> {
|
||||
debugger
|
||||
const resp = await ExpenseRepository.GetTranctionList(employeeId);
|
||||
return resp.data
|
||||
},
|
||||
@ -466,4 +465,5 @@ export const useCreateRecurringExpense = (onSuccessCallBack) => {
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -23,16 +23,16 @@ const AdvancePaymentPage = () => {
|
||||
{ label: "Advance Payment" },
|
||||
]}
|
||||
/>
|
||||
<div className="card px-2 py-2 page-min-h">
|
||||
<div className="card px-4 py-2 page-min-h ">
|
||||
<div className="row">
|
||||
<div className="col-12 ">
|
||||
<div className="d-block w-max w-25 text-start" >
|
||||
<Label>Search Employee</Label>
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="d-block text-start" >
|
||||
<EmployeeSearchInput
|
||||
control={control}
|
||||
name="employeeId"
|
||||
projectId={null}
|
||||
forAll={true}
|
||||
placeholder={"Enter Employee Name"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,11 +49,11 @@ const ExpenseRepository = {
|
||||
CreateRecurringExpense: (data) => api.post("/api/Expense/recurring-payment/create", data),
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//#region Advance Payment
|
||||
GetTranctionList: () => api.get(`/get/transactions/${employeeId}`),
|
||||
GetTranctionList: (employeeId)=>api.get(`/api/Expense/get/transactions/${employeeId}`),
|
||||
//#endregion
|
||||
|
||||
};
|
||||
|
||||
export default ExpenseRepository;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user