import type { FastifyPluginAsync } from 'fastify' import { PaginationSchema, RepairTicketCreateSchema, RepairTicketUpdateSchema, RepairTicketStatusUpdateSchema, RepairLineItemCreateSchema, RepairLineItemUpdateSchema, RepairBatchCreateSchema, RepairBatchUpdateSchema, RepairBatchStatusUpdateSchema, RepairNoteCreateSchema, RepairServiceTemplateCreateSchema, RepairServiceTemplateUpdateSchema, } from '@lunarfront/shared/schemas' import { RepairTicketService, RepairLineItemService, RepairBatchService, RepairNoteService, RepairServiceTemplateService } from '../../services/repair.service.js' export const repairRoutes: FastifyPluginAsync = async (app) => { // --- Repair Tickets --- app.post('/repair-tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const parsed = RepairTicketCreateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const ticket = await RepairTicketService.create(app.db, parsed.data) return reply.status(201).send(ticket) }) app.get('/repair-tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const query = request.query as Record const params = PaginationSchema.parse(query) const filters = { status: query.status?.split(',').filter(Boolean), conditionIn: query.conditionIn?.split(',').filter(Boolean), isBatch: query.isBatch === 'true' ? true : query.isBatch === 'false' ? false : undefined, batchNumber: query.batchNumber, intakeDateFrom: query.intakeDateFrom, intakeDateTo: query.intakeDateTo, promisedDateFrom: query.promisedDateFrom, promisedDateTo: query.promisedDateTo, completedDateFrom: query.completedDateFrom, completedDateTo: query.completedDateTo, } const result = await RepairTicketService.list(app.db, params, filters) return reply.send(result) }) app.get('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const { id } = request.params as { id: string } const ticket = await RepairTicketService.getById(app.db, id) if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } }) return reply.send(ticket) }) app.patch('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { id } = request.params as { id: string } const parsed = RepairTicketUpdateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const ticket = await RepairTicketService.update(app.db, id, parsed.data) if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } }) return reply.send(ticket) }) app.post('/repair-tickets/:id/status', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { id } = request.params as { id: string } const parsed = RepairTicketStatusUpdateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const ticket = await RepairTicketService.updateStatus(app.db, id, parsed.data.status) if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } }) return reply.send(ticket) }) app.delete('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const ticket = await RepairTicketService.delete(app.db, id) if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } }) return reply.send(ticket) }) // --- Repair Line Items --- app.post('/repair-tickets/:ticketId/line-items', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { ticketId } = request.params as { ticketId: string } const parsed = RepairLineItemCreateSchema.safeParse({ ...(request.body as object), repairTicketId: ticketId }) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const item = await RepairLineItemService.create(app.db, parsed.data) return reply.status(201).send(item) }) app.get('/repair-tickets/:ticketId/line-items', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const { ticketId } = request.params as { ticketId: string } const params = PaginationSchema.parse(request.query) const result = await RepairLineItemService.listByTicket(app.db, ticketId, params) return reply.send(result) }) app.patch('/repair-line-items/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { id } = request.params as { id: string } const parsed = RepairLineItemUpdateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const item = await RepairLineItemService.update(app.db, id, parsed.data) if (!item) return reply.status(404).send({ error: { message: 'Line item not found', statusCode: 404 } }) return reply.send(item) }) app.delete('/repair-line-items/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const item = await RepairLineItemService.delete(app.db, id) if (!item) return reply.status(404).send({ error: { message: 'Line item not found', statusCode: 404 } }) return reply.send(item) }) // --- Repair Batches --- app.post('/repair-batches', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const parsed = RepairBatchCreateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const batch = await RepairBatchService.create(app.db, parsed.data) return reply.status(201).send(batch) }) app.get('/repair-batches', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const params = PaginationSchema.parse(request.query) const result = await RepairBatchService.list(app.db, params) return reply.send(result) }) app.get('/repair-batches/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const { id } = request.params as { id: string } const batch = await RepairBatchService.getById(app.db, id) if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } }) return reply.send(batch) }) app.patch('/repair-batches/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { id } = request.params as { id: string } const parsed = RepairBatchUpdateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const batch = await RepairBatchService.update(app.db, id, parsed.data) if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } }) return reply.send(batch) }) app.post('/repair-batches/:id/status', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { id } = request.params as { id: string } const parsed = RepairBatchStatusUpdateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const batch = await RepairBatchService.updateStatus(app.db, id, parsed.data.status) if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } }) return reply.send(batch) }) app.post('/repair-batches/:id/approve', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const batch = await RepairBatchService.approve(app.db, id, request.user.id) if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } }) return reply.send(batch) }) app.post('/repair-batches/:id/reject', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const batch = await RepairBatchService.reject(app.db, id) if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } }) return reply.send(batch) }) app.get('/repair-batches/:batchId/tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const { batchId } = request.params as { batchId: string } const params = PaginationSchema.parse(request.query) const result = await RepairTicketService.listByBatch(app.db, batchId, params) return reply.send(result) }) // --- Repair Notes --- app.post('/repair-tickets/:ticketId/notes', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => { const { ticketId } = request.params as { ticketId: string } const parsed = RepairNoteCreateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const ticket = await RepairTicketService.getById(app.db, ticketId) if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } }) // Look up author name from users table const { users } = await import('../../db/schema/users.js') const { eq } = await import('drizzle-orm') const [author] = await app.db.select({ firstName: users.firstName, lastName: users.lastName }).from(users).where(eq(users.id, request.user.id)).limit(1) const authorName = author ? `${author.firstName} ${author.lastName}` : 'Unknown' const note = await RepairNoteService.create(app.db, ticketId, request.user.id, authorName, ticket.status, parsed.data) return reply.status(201).send(note) }) app.get('/repair-tickets/:ticketId/notes', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const { ticketId } = request.params as { ticketId: string } const params = PaginationSchema.parse(request.query) const result = await RepairNoteService.listByTicket(app.db, ticketId, params) return reply.send(result) }) app.delete('/repair-notes/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const note = await RepairNoteService.delete(app.db, id) if (!note) return reply.status(404).send({ error: { message: 'Note not found', statusCode: 404 } }) return reply.send(note) }) // --- Repair Service Templates --- app.post('/repair-service-templates', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const parsed = RepairServiceTemplateCreateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const template = await RepairServiceTemplateService.create(app.db, parsed.data) return reply.status(201).send(template) }) app.get('/repair-service-templates', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => { const params = PaginationSchema.parse(request.query) const result = await RepairServiceTemplateService.list(app.db, params) return reply.send(result) }) app.patch('/repair-service-templates/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const parsed = RepairServiceTemplateUpdateSchema.safeParse(request.body) if (!parsed.success) { return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } }) } const template = await RepairServiceTemplateService.update(app.db, id, parsed.data) if (!template) return reply.status(404).send({ error: { message: 'Template not found', statusCode: 404 } }) return reply.send(template) }) app.delete('/repair-service-templates/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => { const { id } = request.params as { id: string } const template = await RepairServiceTemplateService.delete(app.db, id) if (!template) return reply.status(404).send({ error: { message: 'Template not found', statusCode: 404 } }) return reply.send(template) }) }