import { z } from "zod"; import { localToUtc } from "../../utils/appUtils"; const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB const ALLOWED_TYPES = [ "application/pdf", "image/png", "image/jpg", "image/jpeg", ]; export const ExpenseSchema = (expenseTypes) => { return z .object({ projectId: z.string().min(1, { message: "Project is required" }), expensesTypeId: z .string() .min(1, { message: "Expense type is required" }), paymentModeId: z.string().min(1, { message: "Payment mode is required" }), paidById: z.string().min(1, { message: "Employee name is required" }), transactionDate: z.string().min(1, { message: "Date is required" }), transactionId: z.string().optional(), description: z.string().min(1, { message: "Description is required" }), location: z.string().min(1, { message: "Location is required" }), supplerName: z.string().min(1, { message: "Supplier name is required" }), gstNumber: z.string().optional(), amount: z.coerce .number({ invalid_type_error: "Amount is required and must be a number", }) .min(1, "Amount must be Enter") .refine((val) => /^\d+(\.\d{1,2})?$/.test(val.toString()), { message: "Amount must have at most 2 decimal places", }), noOfPersons: z.coerce.number().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" }), }) .refine( (data) => { return ( !data.projectId || (data.paidById && data.paidById.trim() !== "") ); }, { message: "Please select who paid (employee)", path: ["paidById"], } ) .superRefine((data, ctx) => { const expenseType = expenseTypes.find( (et) => et.id === data.expensesTypeId ); if ( expenseType?.noOfPersonsRequired && (!data.noOfPersons || data.noOfPersons < 1) ) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "No. of Persons is required and must be at least 1", path: ["noOfPersons"], }); } }); }; export const defaultExpense = { projectId: "", expensesTypeId: "", paymentModeId: "", paidById: "", transactionDate: "", transactionId: "", description: "", location: "", supplerName: "", amount: "", noOfPersons: "", gstNumber: "", billAttachments: [], }; export const ExpenseActionScheam = ( isReimbursement = false, transactionDate ) => { return z .object({ comment: z.string().min(1, { message: "Please leave comment" }), statusId: z.string().min(1, { message: "Please select a status" }), reimburseTransactionId: z.string().nullable().optional(), reimburseDate: z.string().nullable().optional(), reimburseById: z.string().nullable().optional(), }) .superRefine((data, ctx) => { if (isReimbursement) { if (!data.reimburseTransactionId?.trim()) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["reimburseTransactionId"], message: "Reimburse Transaction ID is required", }); } if (!data.reimburseDate) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["reimburseDate"], message: "Reimburse Date is required", }); } // let reimburse_Date = localToUtc(data.reimburseDate); // if (transactionDate > reimburse_Date) { // ctx.addIssue({ // code: z.ZodIssueCode.custom, // path: ["reimburseDate"], // message: // "Reimburse Date must be greater than or equal to Expense created Date", // }); // } if (!data.reimburseById) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["reimburseById"], message: "Reimburse By is required", }); } } }); }; export const defaultActionValues = { comment: "", statusId: "", reimburseTransactionId: null, reimburseDate: null, reimburseById: null, }; export const SearchSchema = z.object({ projectIds: z.array(z.string()).optional(), statusIds: z.array(z.string()).optional(), createdByIds: z.array(z.string()).optional(), paidById: z.array(z.string()).optional(), ExpenseTypeIds: z.array(z.string()).optional(), startDate: z.string().optional(), endDate: z.string().optional(), isTransactionDate: z.boolean().default(true), }); export const defaultFilter = { projectIds: [], statusIds: [], createdByIds: [], paidById: [], ExpenseTypeIds: [], isTransactionDate: true, startDate: null, endDate: null, };