From ec9bcd1ea5bf48ccd19b519138369d733c853604 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Mon, 10 Nov 2025 16:10:18 +0530 Subject: [PATCH] added validation for Tax , base amount, and added signal for PR and Recurring --- .../PaymentRequest/ActionPaymentRequest.jsx | 134 +++++++++--------- .../PaymentRequest/PaymentRequestSchema.js | 55 +++++-- .../PaymentRequest/PaymentStatusLogs.jsx | 4 +- .../PaymentRequest/ViewPaymentRequest.jsx | 2 +- src/components/common/TimeLine.jsx | 4 +- .../PaymentRequest/PaymentRequestPage.jsx | 2 +- src/services/signalRService.js | 11 +- 7 files changed, 128 insertions(+), 84 deletions(-) diff --git a/src/components/PaymentRequest/ActionPaymentRequest.jsx b/src/components/PaymentRequest/ActionPaymentRequest.jsx index 8d2d9c96..b03f2c8e 100644 --- a/src/components/PaymentRequest/ActionPaymentRequest.jsx +++ b/src/components/PaymentRequest/ActionPaymentRequest.jsx @@ -254,68 +254,67 @@ const ActionPaymentRequest = ({ requestId }) => { )} -
- +
+ -
- document.getElementById("billAttachments").click() - } - > - - - Click to select or click here to browse - - - (PDF, JPG, PNG, max 5MB) - +
+ document.getElementById("billAttachments").click() + } + > + + + Click to select or click here to browse + + + (PDF, JPG, PNG, max 5MB) + - { - onFileChange(e); - e.target.value = ""; - }} - /> -
- {errors.billAttachments && ( - - {errors.billAttachments.message} - - )} - {files?.length > 0 && ( - - )} - - {Array.isArray(errors.billAttachments) && - errors.billAttachments.map((fileError, index) => ( -
- { - (fileError?.fileSize?.message || - fileError?.contentType?.message || - fileError?.base64Data?.message, - fileError?.documentId?.message) - } -
- ))} + { + onFileChange(e); + e.target.value = ""; + }} + />
+ {errors.billAttachments && ( + + {errors.billAttachments.message} + + )} + {files?.length > 0 && ( + + )} + + {Array.isArray(errors.billAttachments) && + errors.billAttachments.map((fileError, index) => ( +
+ { + (fileError?.fileSize?.message || + fileError?.contentType?.message || + fileError?.base64Data?.message, + fileError?.documentId?.message) + } +
+ ))}
- +
) : ( @@ -358,9 +357,11 @@ const ActionPaymentRequest = ({ requestId }) => {
{errors.tdsPercentage && ( @@ -373,9 +374,11 @@ const ActionPaymentRequest = ({ requestId }) => { Base Amount {errors.baseAmount && ( @@ -388,9 +391,11 @@ const ActionPaymentRequest = ({ requestId }) => { Tax Amount {errors.taxAmount && ( @@ -406,7 +411,6 @@ const ActionPaymentRequest = ({ requestId }) => { {((nextStatusWithPermission?.length > 0 && !isRejectedRequest) || (isRejectedRequest && isCreatedBy)) && ( <> - diff --git a/src/components/PaymentRequest/PaymentRequestSchema.js b/src/components/PaymentRequest/PaymentRequestSchema.js index 03ae49df..d12f1cac 100644 --- a/src/components/PaymentRequest/PaymentRequestSchema.js +++ b/src/components/PaymentRequest/PaymentRequestSchema.js @@ -1,6 +1,10 @@ - import { boolean, z } from "zod"; -import { CREATE_EXEPENSE, EXPENSE_DRAFT, EXPENSE_STATUS, INR_CURRENCY_CODE } from "../../utils/constants"; +import { + CREATE_EXEPENSE, + EXPENSE_DRAFT, + EXPENSE_STATUS, + INR_CURRENCY_CODE, +} from "../../utils/constants"; const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB const ALLOWED_TYPES = [ "application/pdf", @@ -93,9 +97,24 @@ 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(), + tdsPercentage: z + .number({ invalid_type_error: "TDS must be a number" }) + .min(0, { message: "TDS must be zero or greater" }) + .or(z.nan()) + .or(z.null()) + .optional(), + baseAmount: z + .number({ invalid_type_error: "TDS must be a number" }) + .min(0, { message: "TDS must be zero or greater" }) + .or(z.nan()) + .or(z.null()) + .optional(), + taxAmount: z + .number({ invalid_type_error: "Tax amount must be a number" }) + .min(0, { message: "Tax amount must be zero or greater" }) + .or(z.nan()) + .or(z.null()) + .optional(), // after Payment Processed paymentModeId: z.string().nullable().optional(), location: z.string().nullable().optional(), @@ -139,18 +158,31 @@ export const PaymentRequestActionScheam = ( message: "Paid By is required", }); } - if (!data.baseAmount) { + if (!data.baseAmount || data.baseAmount < 0) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["baseAmount"], - message: "Base Amount i required", + message: "Base Amount is required", }); } - if (!data.taxAmount) { + if ( + data.taxAmount === null || + data.taxAmount === undefined || + isNaN(Number(data.taxAmount)) || + Number(data.taxAmount) < 0 + ) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["taxAmount"], - message: "Tax is required", + message: "Tax amount must be zero or greater", + }); + } + + if (data.tdsPercentage < 0) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["tdsPercentage"], + message: "TDS must valid", }); } } @@ -186,9 +218,9 @@ export const defaultPRActionValues = { paidTransactionId: null, paidAt: null, paidById: null, - tdsPercentage: "0", + tdsPercentage: null, baseAmount: null, - taxAmount: "0", + taxAmount: 0, // after Payment Processed paymentModeId: null, location: null, @@ -227,7 +259,6 @@ export const DefaultRequestedExpense = { billAttachments: [], }; - export const STATUS_HEADING = { [EXPENSE_STATUS.draft]: "Initiation", [EXPENSE_STATUS.review_pending]: "Review & Validation", diff --git a/src/components/PaymentRequest/PaymentStatusLogs.jsx b/src/components/PaymentRequest/PaymentStatusLogs.jsx index f6ba6833..f8c8006c 100644 --- a/src/components/PaymentRequest/PaymentStatusLogs.jsx +++ b/src/components/PaymentRequest/PaymentStatusLogs.jsx @@ -38,9 +38,9 @@ const PaymentStatusLogs = ({ data }) => { }; return (
-
+
{" "} -

TimeLine

+

TimeLine

diff --git a/src/components/PaymentRequest/ViewPaymentRequest.jsx b/src/components/PaymentRequest/ViewPaymentRequest.jsx index f5313a2b..e8cd0823 100644 --- a/src/components/PaymentRequest/ViewPaymentRequest.jsx +++ b/src/components/PaymentRequest/ViewPaymentRequest.jsx @@ -146,7 +146,7 @@ const ViewPaymentRequest = ({ requestId }) => {
- {data?.paymentRequestUID} +
PR No : {data?.paymentRequestUID}
{ {moment.utc(item.timeAgo).local().fromNow()}
- {item.description &&

{item.description}

} + {item.description &&

{item.description}

} {item.attachments && item.attachments.length > 0 && (
@@ -93,7 +93,7 @@ const Timeline = ({ items = [], transparent = true }) => {
)} -
{item.userComment &&

{item.userComment}

}
+
{item.userComment &&

{item.userComment}

}
))} diff --git a/src/pages/PaymentRequest/PaymentRequestPage.jsx b/src/pages/PaymentRequest/PaymentRequestPage.jsx index 541a366e..f530f5b0 100644 --- a/src/pages/PaymentRequest/PaymentRequestPage.jsx +++ b/src/pages/PaymentRequest/PaymentRequestPage.jsx @@ -132,7 +132,7 @@ const PaymentRequestPage = () => { {ViewRequest.view && ( setVieRequest({ requestId: null, view: false })} > diff --git a/src/services/signalRService.js b/src/services/signalRService.js index 05ff808a..7348fbad 100644 --- a/src/services/signalRService.js +++ b/src/services/signalRService.js @@ -40,6 +40,14 @@ export function startSignalR(loggedUser) { // ---- Handlers for invalidate or remove ---- const queryInvalidators = { + Payment_Request: () => { + queryClient.invalidateQueries({ queryKey: ["recurringExpenseList"] }), + queryClient.invalidateQueries({ queryKey: ["recurringExpenseList"] }); + }, + Recurring_Payment: () => { + queryClient.invalidateQueries({ queryKey: ["paymentRequestList"] }), + queryClient.invalidateQueries({ queryKey: ["paymentRequest"] }); + }, Expanse: () => { queryClient.invalidateQueries({ queryKey: ["Expenses"] }), queryClient.invalidateQueries({ queryKey: ["Expense"] }); @@ -79,7 +87,8 @@ export function startSignalR(loggedUser) { if (today === checkIn) eventBus.emit("attendance", data); const onlyDate = Number(checkIn.substring(8, 10)); - const afterTwoDay = checkIn.substring(0,8) + (onlyDate + 2).toString().padStart(2, "0"); + const afterTwoDay = + checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0"); if ( afterTwoDay <= today && (response.activity === 4 || response.activity === 5)