/** * Billing Domain - Schemas * * Zod validation schemas for billing domain types. * Used for runtime validation of data from any source. */ import { z } from "zod"; // Invoice Status Schema export const invoiceStatusSchema = z.enum([ "Draft", "Pending", "Paid", "Unpaid", "Overdue", "Cancelled", "Refunded", "Collections", ]); // Invoice Item Schema export const invoiceItemSchema = z.object({ id: z.number().int().positive("Invoice item id must be positive"), description: z.string().min(1, "Description is required"), amount: z.number(), quantity: z.number().int().positive("Quantity must be positive").optional(), type: z.string().min(1, "Item type is required"), serviceId: z.number().int().positive().optional(), }); // Invoice Schema export const invoiceSchema = z.object({ id: z.number().int().positive("Invoice id must be positive"), number: z.string().min(1, "Invoice number is required"), status: invoiceStatusSchema, currency: z.string().min(1, "Currency is required"), currencySymbol: z.string().min(1, "Currency symbol is required").optional(), total: z.number(), subtotal: z.number(), tax: z.number(), issuedAt: z.string().optional(), dueDate: z.string().optional(), paidDate: z.string().optional(), pdfUrl: z.string().optional(), paymentUrl: z.string().optional(), description: z.string().optional(), items: z.array(invoiceItemSchema).optional(), daysOverdue: z.number().int().nonnegative().optional(), }); // Invoice Pagination Schema export const invoicePaginationSchema = z.object({ page: z.number().int().nonnegative(), totalPages: z.number().int().nonnegative(), totalItems: z.number().int().nonnegative(), nextCursor: z.string().optional(), }); // Invoice List Schema export const invoiceListSchema = z.object({ invoices: z.array(invoiceSchema), pagination: invoicePaginationSchema, }); // Invoice SSO Link Schema export const invoiceSsoLinkSchema = z.object({ url: z.string().url(), expiresAt: z.string(), }); // Payment Invoice Request Schema export const paymentInvoiceRequestSchema = z.object({ invoiceId: z.number().int().positive(), paymentMethodId: z.number().int().positive().optional(), gatewayName: z.string().optional(), amount: z.number().positive().optional(), }); // Billing Summary Schema export const billingSummarySchema = z.object({ totalOutstanding: z.number(), totalOverdue: z.number(), totalPaid: z.number(), currency: z.string(), currencySymbol: z.string().optional(), invoiceCount: z.object({ total: z.number().int().min(0), unpaid: z.number().int().min(0), overdue: z.number().int().min(0), paid: z.number().int().min(0), }), }); // ============================================================================ // Query Parameter Schemas // ============================================================================ /** * Schema for invoice list query parameters */ export const invoiceQueryParamsSchema = z.object({ page: z.coerce.number().int().positive().optional(), limit: z.coerce.number().int().positive().max(100).optional(), status: invoiceStatusSchema.optional(), dateFrom: z.string().datetime().optional(), dateTo: z.string().datetime().optional(), }); export type InvoiceQueryParams = z.infer; const invoiceListStatusSchema = z.enum(["Paid", "Unpaid", "Cancelled", "Overdue", "Collections"]); export const invoiceListQuerySchema = z.object({ page: z.coerce.number().int().positive().optional(), limit: z.coerce.number().int().positive().max(100).optional(), status: invoiceListStatusSchema.optional(), }); export type InvoiceListQuery = z.infer; // ============================================================================ // Inferred Types from Schemas (Schema-First Approach) // ============================================================================ export type InvoiceStatus = z.infer; export type InvoiceItem = z.infer; export type Invoice = z.infer; export type InvoicePagination = z.infer; export type InvoiceList = z.infer; export type InvoiceSsoLink = z.infer; export type PaymentInvoiceRequest = z.infer; export type BillingSummary = z.infer;