88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import { z } from "zod"
|
|
import { PaymentFor } from "@garage/api"
|
|
|
|
const relationFieldSchema = z
|
|
.object({ value: z.string(), label: z.string() })
|
|
.nullable()
|
|
|
|
const requiredRelationFieldSchema = relationFieldSchema.superRefine((value, ctx) => {
|
|
if (!value?.value) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: "This field is required",
|
|
})
|
|
}
|
|
})
|
|
|
|
const optionalStringMax255Schema = z.preprocess(
|
|
(value) => (value === "" || value == null ? undefined : value),
|
|
z.string().max(255, "Must be at most 255 characters").optional(),
|
|
)
|
|
|
|
const detailsItemSchema = z.object({
|
|
bill_id: z.union([z.string(), z.number()]).optional().nullable(),
|
|
expense_id: z.union([z.string(), z.number()]).optional().nullable(),
|
|
amount_paid: z.coerce.number().min(0).optional(),
|
|
})
|
|
|
|
const paymentMadeFormSchema = z.object({
|
|
// ── Relations ──
|
|
bill: relationFieldSchema,
|
|
vendor: relationFieldSchema,
|
|
employee: relationFieldSchema,
|
|
payment_mode: requiredRelationFieldSchema,
|
|
|
|
// ── Payment info ──
|
|
amount: z.coerce.number().min(0, "Amount must be 0 or more"),
|
|
payment_for: z.enum(PaymentFor),
|
|
payment_number: optionalStringMax255Schema,
|
|
payment_reference: optionalStringMax255Schema,
|
|
payment_date: z.string().min(1, "Payment date is required").date("Enter a valid date"),
|
|
paid_through: optionalStringMax255Schema,
|
|
notes: z.string().optional(),
|
|
details: z.array(detailsItemSchema).min(1, "At least one payment detail is required"),
|
|
}).superRefine((values, ctx) => {
|
|
const hasBill = Boolean(values.bill?.value)
|
|
const hasVendor = Boolean(values.vendor?.value)
|
|
const hasEmployee = Boolean(values.employee?.value)
|
|
|
|
if (values.payment_for === "bill" && !hasBill) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
path: ["bill"],
|
|
message: "Bill is required",
|
|
})
|
|
}
|
|
|
|
if (!hasVendor && !hasEmployee) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
path: ["vendor"],
|
|
message: "Vendor or employee is required",
|
|
})
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
path: ["employee"],
|
|
message: "Vendor or employee is required",
|
|
})
|
|
}
|
|
|
|
if (hasVendor && hasEmployee) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
path: ["vendor"],
|
|
message: "Select either a vendor or an employee, not both",
|
|
})
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
path: ["employee"],
|
|
message: "Select either a vendor or an employee, not both",
|
|
})
|
|
}
|
|
})
|
|
|
|
type PaymentMadeFormValues = z.infer<typeof paymentMadeFormSchema>
|
|
|
|
export { paymentMadeFormSchema, relationFieldSchema }
|
|
export type { PaymentMadeFormValues }
|