diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 2e96665..4d713bf 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -769,7 +769,7 @@ model HostParent { id Int @id @default(autoincrement()) hostXid Int @map("host_xid") host HostHeader @relation(fields: [hostXid], references: [id], onDelete: Cascade) - companyName String @map("company_name") @db.VarChar(50) + companyName String @map("company_name") @db.VarChar(100) address1 String? @map("address_1") @db.VarChar(150) address2 String? @map("address_2") @db.VarChar(150) cityXid Int? @map("city_xid") @@ -807,7 +807,7 @@ model HostParenetDocuments { hostParent HostParent @relation(fields: [hostParentXid], references: [id], onDelete: Cascade) documentTypeXid Int @map("document_type_xid") documentType DocumentType @relation(fields: [documentTypeXid], references: [id], onDelete: Restrict) - documentName String @map("document_name") @db.VarChar(30) + documentName String @map("document_name") @db.VarChar(50) filePath String @map("file_path") @db.VarChar(400) isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") diff --git a/src/common/utils/validation/host/hostCompanyDetails.validation.ts b/src/common/utils/validation/host/hostCompanyDetails.validation.ts index 2a8d14c..c480786 100644 --- a/src/common/utils/validation/host/hostCompanyDetails.validation.ts +++ b/src/common/utils/validation/host/hostCompanyDetails.validation.ts @@ -1,83 +1,135 @@ import { z } from "zod"; -// REQUIRED_DOC_TYPES (use your mapping) -// export const REQUIRED_DOC_TYPES = { -// GST: 1, -// PAN: 2, -// REGISTRATION: 3, -// AADHAAR: 4, -// }; - export const parentCompanySchema = z.object({ - companyName: z.string().min(1, "Parent company name is required"), - address1: z.string().min(1, "Address1 is required"), - address2: z.string().optional(), + companyName: z.string() + .min(1, "Parent company name is required") + .max(100, "Parent company name cannot exceed 100 characters"), - // Parent companies DO NOT need this + address1: z.string() + .min(1, "Address1 is required") + .max(150, "Address1 cannot exceed 150 characters"), + + address2: z.string() + .max(150, "Address2 cannot exceed 150 characters") + .optional(), cityXid: z.number().min(1, "City is required"), stateXid: z.number().min(1, "State is required"), countryXid: z.number().min(1, "Country is required"), - pinCode: z.string().min(4, "Pincode/Zipcode is required"), + pinCode: z.string() + .min(4, "Pincode/Zipcode is required") + .max(30, "Pincode cannot exceed 30 characters"), - logoPath: z.string().optional(), + logoPath: z.string() + .max(400, "Logo path cannot exceed 400 characters") + .optional(), - // Parent companies do NOT need this isSubsidairy: z.boolean().optional(), - registrationNumber: z.string().optional(), - panNumber: z.string().optional(), - gstNumber: z.string().optional(), + registrationNumber: z.string() + .max(30, "Registration number cannot exceed 30 characters") + .optional(), - formationDate: z.string().optional().refine((val) => !isNaN(Date.parse(val)), { - message: "Formation date must be a valid date", - }), + panNumber: z.string() + .max(30, "PAN number cannot exceed 30 characters") + .optional(), - companyType: z.string().min(1, "Company type is required"), - websiteUrl: z.string().url().optional(), - instagramUrl: z.string().url().optional(), - facebookUrl: z.string().url().optional(), - linkedinUrl: z.string().url().optional(), - twitterUrl: z.string().url().optional(), + gstNumber: z.string() + .max(30, "GST number cannot exceed 30 characters") + .optional(), + formationDate: z.string() + .optional() + .refine((val) => !val || !isNaN(Date.parse(val)), { + message: "Formation date must be a valid date", + }), + + companyType: z.string() + .min(1, "Company type is required") + .max(30, "Company type cannot exceed 30 characters"), + + websiteUrl: z.string().url().max(80, "Website URL cannot exceed 80 characters").optional(), + instagramUrl: z.string().url().max(80, "Instagram URL cannot exceed 80 characters").optional(), + facebookUrl: z.string().url().max(80, "Facebook URL cannot exceed 80 characters").optional(), + linkedinUrl: z.string().url().max(80, "LinkedIn URL cannot exceed 80 characters").optional(), + twitterUrl: z.string().url().max(80, "Twitter URL cannot exceed 80 characters").optional(), }); +// ======================================================= +// HOST COMPANY DETAILS (Main Company) +// ======================================================= + export const hostCompanyDetailsSchema = z.object({ - companyName: z.string().min(1, "Company name is required"), - address1: z.string().min(1, "Address1 is required"), - address2: z.string().optional(), + companyName: z.string() + .min(1, "Company name is required") + .max(100, "Company name cannot exceed 100 characters"), + + address1: z.string() + .min(1, "Address1 is required") + .max(150, "Address1 cannot exceed 150 characters"), + + address2: z.string() + .max(150, "Address2 cannot exceed 150 characters") + .optional(), + cityXid: z.number().min(1, "City is required"), stateXid: z.number().min(1, "State is required"), - countryXid: z.number().min(1,"Country is required"), - pinCode: z.string().min(4, "Pincode/Zipcode is required"), - logoPath: z.string().optional(), - isSubsidairy: z.boolean(), - registrationNumber: z.string().optional(), - panNumber: z.string().min(1, "PAN number is required"), - gstNumber: z.string().optional(), - formationDate: z.string().optional().refine((val) => !isNaN(Date.parse(val)), { - message: "Formation date must be a valid date", - }), - companyType: z.string().min(1, "Company type is required"), - websiteUrl: z.string().url().optional(), - instagramUrl: z.string().url().optional(), - facebookUrl: z.string().url().optional(), - linkedinUrl: z.string().url().optional(), - twitterUrl: z.string().url().optional(), + countryXid: z.number().min(1, "Country is required"), + + pinCode: z.string() + .min(4, "Pincode/Zipcode is required") + .max(30, "Pincode cannot exceed 30 characters"), + + logoPath: z.string() + .max(400, "Logo path cannot exceed 400 characters") + .optional(), + + isSubsidairy: z.boolean(), + + registrationNumber: z.string() + .max(30, "Registration number cannot exceed 30 characters") + .optional(), + + panNumber: z.string() + .min(1, "PAN number is required") + .max(30, "PAN number cannot exceed 30 characters"), + + gstNumber: z.string() + .max(30, "GST number cannot exceed 30 characters") + .optional(), + + formationDate: z.string() + .optional() + .refine((val) => !val || !isNaN(Date.parse(val)), { + message: "Formation date must be a valid date", + }), + + companyType: z.string() + .min(1, "Company type is required") + .max(30, "Company type cannot exceed 30 characters"), + + websiteUrl: z.string().url().max(50, "Website URL cannot exceed 50 characters").optional(), + instagramUrl: z.string().url().max(80, "Instagram URL cannot exceed 80 characters").optional(), + facebookUrl: z.string().url().max(80, "Facebook URL cannot exceed 80 characters").optional(), + linkedinUrl: z.string().url().max(80, "LinkedIn URL cannot exceed 80 characters").optional(), + twitterUrl: z.string().url().max(80, "Twitter URL cannot exceed 80 characters").optional(), - // Parent company nested when this is subsidiary parentCompany: parentCompanySchema.optional(), }); -// Documents schema: added optional owner + +// ======================================================= +// DOCUMENTS VALIDATION +// ======================================================= + export const hostDocumentsSchema = z.array( z.object({ documentTypeXid: z.number(), - documentName: z.string(), - fieldName: z.string(), // maps to the multipart file field - owner: z.enum(['host', 'parent']).optional(), // default to host - isOptional: z.boolean().optional(), // optional docs flag if frontend provides it + documentName: z.string().max(50, "Document name cannot exceed 50 characters"), // per parent max 50 / host max 20 — safe limit 50 + fieldName: z.string(), + owner: z.enum(['host', 'parent']).optional(), + isOptional: z.boolean().optional(), }) );