Files
lunarfront-app/packages/shared/src/schemas/repairs.schema.ts
Ryan Moon 9400828f62 Rename Forte to LunarFront, generalize for any small business
Rebrand from Forte (music-store-specific) to LunarFront (any small business):
- Package namespace @forte/* → @lunarfront/*
- Database forte/forte_test → lunarfront/lunarfront_test
- Docker containers, volumes, connection strings
- UI branding, localStorage keys, test emails
- All documentation and planning docs

Generalize music-specific terminology:
- instrumentDescription → itemDescription
- instrumentCount → itemCount
- instrumentType → itemCategory (on service templates)
- New migration 0027_generalize_terminology for column renames
- Seed data updated with generic examples
- RBAC descriptions updated
2026-03-30 08:51:54 -05:00

127 lines
4.9 KiB
TypeScript

import { z } from 'zod'
/** Coerce empty strings to undefined — solves HTML form inputs sending '' for blank optional fields */
function opt<T extends z.ZodTypeAny>(schema: T) {
return z.preprocess((v) => (v === '' ? undefined : v), schema.optional())
}
// --- Status / Type enums ---
export const RepairTicketStatus = z.enum([
'new', 'in_transit', 'intake', 'diagnosing', 'pending_approval', 'approved',
'in_progress', 'pending_parts', 'ready', 'picked_up', 'delivered', 'cancelled',
])
export type RepairTicketStatus = z.infer<typeof RepairTicketStatus>
export const RepairLineItemType = z.enum(['labor', 'part', 'flat_rate', 'misc'])
export type RepairLineItemType = z.infer<typeof RepairLineItemType>
export const RepairConditionIn = z.enum(['excellent', 'good', 'fair', 'poor'])
export type RepairConditionIn = z.infer<typeof RepairConditionIn>
export const RepairBatchStatus = z.enum([
'intake', 'in_progress', 'pending_approval', 'approved', 'completed', 'delivered', 'cancelled',
])
export type RepairBatchStatus = z.infer<typeof RepairBatchStatus>
export const RepairBatchApproval = z.enum(['pending', 'approved', 'rejected'])
export type RepairBatchApproval = z.infer<typeof RepairBatchApproval>
// --- Repair Ticket schemas ---
export const RepairTicketCreateSchema = z.object({
customerName: z.string().min(1).max(255),
customerPhone: opt(z.string().max(50)),
accountId: opt(z.string().uuid()),
locationId: opt(z.string().uuid()),
repairBatchId: opt(z.string().uuid()),
inventoryUnitId: opt(z.string().uuid()),
itemDescription: opt(z.string()),
serialNumber: opt(z.string().max(255)),
conditionIn: opt(RepairConditionIn),
conditionInNotes: opt(z.string()),
problemDescription: z.string().min(1),
technicianNotes: opt(z.string()),
assignedTechnicianId: opt(z.string().uuid()),
estimatedCost: z.coerce.number().min(0).optional(),
promisedDate: opt(z.string()),
})
export type RepairTicketCreateInput = z.infer<typeof RepairTicketCreateSchema>
export const RepairTicketUpdateSchema = RepairTicketCreateSchema.partial()
export type RepairTicketUpdateInput = z.infer<typeof RepairTicketUpdateSchema>
export const RepairTicketStatusUpdateSchema = z.object({
status: RepairTicketStatus,
})
export type RepairTicketStatusUpdateInput = z.infer<typeof RepairTicketStatusUpdateSchema>
// --- Repair Line Item schemas ---
export const RepairLineItemCreateSchema = z.object({
repairTicketId: z.string().uuid(),
itemType: RepairLineItemType,
description: z.string().min(1).max(255),
productId: opt(z.string().uuid()),
qty: z.coerce.number().min(0).default(1),
unitPrice: z.coerce.number().min(0).default(0),
totalPrice: z.coerce.number().min(0).default(0),
cost: z.coerce.number().min(0).optional(),
technicianId: opt(z.string().uuid()),
})
export type RepairLineItemCreateInput = z.infer<typeof RepairLineItemCreateSchema>
export const RepairLineItemUpdateSchema = RepairLineItemCreateSchema.omit({ repairTicketId: true }).partial()
export type RepairLineItemUpdateInput = z.infer<typeof RepairLineItemUpdateSchema>
// --- Repair Batch schemas ---
export const RepairBatchCreateSchema = z.object({
accountId: z.string().uuid(),
locationId: opt(z.string().uuid()),
contactName: opt(z.string().max(255)),
contactPhone: opt(z.string().max(50)),
contactEmail: opt(z.string().email()),
pickupDate: opt(z.string()),
dueDate: opt(z.string()),
itemCount: z.coerce.number().int().min(0).default(0),
notes: opt(z.string()),
})
export type RepairBatchCreateInput = z.infer<typeof RepairBatchCreateSchema>
export const RepairBatchUpdateSchema = RepairBatchCreateSchema.partial()
export type RepairBatchUpdateInput = z.infer<typeof RepairBatchUpdateSchema>
export const RepairBatchStatusUpdateSchema = z.object({
status: RepairBatchStatus,
})
export type RepairBatchStatusUpdateInput = z.infer<typeof RepairBatchStatusUpdateSchema>
// --- Repair Note schemas ---
export const RepairNoteVisibility = z.enum(['internal', 'customer'])
export type RepairNoteVisibility = z.infer<typeof RepairNoteVisibility>
export const RepairNoteCreateSchema = z.object({
content: z.string().min(1),
visibility: RepairNoteVisibility.default('internal'),
})
export type RepairNoteCreateInput = z.infer<typeof RepairNoteCreateSchema>
// --- Repair Service Template schemas ---
export const RepairServiceTemplateCreateSchema = z.object({
name: z.string().min(1).max(255),
itemCategory: opt(z.string().max(100)),
size: opt(z.string().max(50)),
description: opt(z.string()),
itemType: RepairLineItemType.default('flat_rate'),
defaultPrice: z.coerce.number().min(0).default(0),
defaultCost: z.coerce.number().min(0).optional(),
sortOrder: z.coerce.number().int().default(0),
})
export type RepairServiceTemplateCreateInput = z.infer<typeof RepairServiceTemplateCreateSchema>
export const RepairServiceTemplateUpdateSchema = RepairServiceTemplateCreateSchema.partial()
export type RepairServiceTemplateUpdateInput = z.infer<typeof RepairServiceTemplateUpdateSchema>