import { z } from "zod" import { InvoiceDiscount, InvoiceStatus } from "@garage/api" const relationFieldSchema = z .object({ value: z.string(), label: z.string() }) .nullable() const requiredDateSchema = z .string() .min(1, "This field is required") .date("Enter a valid date") const invoicePartItemSchema = z.object({ part_id: z.number(), title: z.string(), quantity: z.number().min(1), rate: z.number().min(0), discount_amount: z.number().min(0).optional(), description: z.string().optional(), }) const invoiceServiceItemSchema = z.object({ service_id: z.number(), title: z.string(), quantity: z.number().min(1), rate: z.number().min(0), discount_amount: z.number().min(0).optional(), description: z.string().optional(), }) const invoiceExpenseItemSchema = z.object({ expense_id: z.number(), title: z.string(), quantity: z.number().min(1), rate: z.number().min(0), discount_amount: z.number().min(0).optional(), description: z.string().optional(), }) const invoiceFormSchema = z.object({ // ── Required fields ── subject: z.string().trim().min(1, "Subject is required").max(255, "Subject must be at most 255 characters"), // ── Relations ── customer: relationFieldSchema, vehicle: relationFieldSchema, department: relationFieldSchema, estimate: relationFieldSchema, payment_terms: relationFieldSchema, invoice_sequence: relationFieldSchema, payment_mode: relationFieldSchema, insurer: relationFieldSchema, invoice_to: relationFieldSchema, // ── Optional fields ── invoice_number: z.string().trim().min(1, "Invoice number is required").max(255, "Invoice number must be at most 255 characters"), invoice_title: z.string().optional(), invoice_date: requiredDateSchema, due_date: requiredDateSchema, status: z.enum(InvoiceStatus).optional(), kms_in: z.coerce.number().optional(), has_insurance: z.boolean().default(false), discount: z.enum(InvoiceDiscount).optional(), discount_amount: z.coerce.number().min(0).optional(), tax: relationFieldSchema, deposit_to: z.string().optional(), notes: z.string().optional(), terms_and_conditions: z.string().optional(), // ── Line items ── parts: z.array(invoicePartItemSchema).optional(), services: z.array(invoiceServiceItemSchema).optional(), expense_items: z.array(invoiceExpenseItemSchema).optional(), }).superRefine((values, ctx) => { if (values.invoice_date && values.due_date) { const invoiceDate = new Date(values.invoice_date) const dueDate = new Date(values.due_date) if (!Number.isNaN(invoiceDate.getTime()) && !Number.isNaN(dueDate.getTime()) && dueDate < invoiceDate) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["due_date"], message: "Due date must be on or after invoice date", }) } } }) type InvoiceFormValues = z.infer type InvoicePartItem = z.infer type InvoiceServiceItem = z.infer type InvoiceExpenseItem = z.infer export { invoiceFormSchema, relationFieldSchema, invoicePartItemSchema, invoiceServiceItemSchema, invoiceExpenseItemSchema } export type { InvoiceFormValues, InvoicePartItem, InvoiceServiceItem, InvoiceExpenseItem }