/** * Service Order Controller * Mecánicas Diesel - ERP Suite * * REST API endpoints for service orders. */ import { Router, Request, Response, NextFunction } from 'express'; import { DataSource } from 'typeorm'; import { ServiceOrderService, ServiceOrderFilters } from '../services/service-order.service'; import { ServiceOrderStatus, ServiceOrderPriority } from '../entities/service-order.entity'; import { OrderItemType } from '../entities/order-item.entity'; // Middleware type for tenant extraction interface TenantRequest extends Request { tenantId?: string; userId?: string; } export function createServiceOrderController(dataSource: DataSource): Router { const router = Router(); const service = new ServiceOrderService(dataSource); // Middleware to extract tenant from request const extractTenant = (req: TenantRequest, res: Response, next: NextFunction) => { const tenantId = req.headers['x-tenant-id'] as string; if (!tenantId) { return res.status(400).json({ error: 'Tenant ID is required' }); } req.tenantId = tenantId; req.userId = req.headers['x-user-id'] as string; next(); }; router.use(extractTenant); /** * Create a new service order * POST /api/service-orders */ router.post('/', async (req: TenantRequest, res: Response) => { try { const order = await service.create(req.tenantId!, req.body, req.userId); res.status(201).json(order); } catch (error) { res.status(400).json({ error: (error as Error).message }); } }); /** * List service orders with filters * GET /api/service-orders */ router.get('/', async (req: TenantRequest, res: Response) => { try { const filters: ServiceOrderFilters = { status: req.query.status as ServiceOrderStatus, priority: req.query.priority as ServiceOrderPriority, customerId: req.query.customerId as string, vehicleId: req.query.vehicleId as string, assignedTo: req.query.assignedTo as string, bayId: req.query.bayId as string, search: req.query.search as string, fromDate: req.query.fromDate ? new Date(req.query.fromDate as string) : undefined, toDate: req.query.toDate ? new Date(req.query.toDate as string) : undefined, }; const pagination = { page: parseInt(req.query.page as string, 10) || 1, limit: Math.min(parseInt(req.query.limit as string, 10) || 20, 100), }; const result = await service.findAll(req.tenantId!, filters, pagination); res.json(result); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); /** * Get orders grouped by status (Kanban) * GET /api/service-orders/kanban */ router.get('/kanban', async (req: TenantRequest, res: Response) => { try { const result = await service.getOrdersByStatus(req.tenantId!); res.json(result); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); /** * Get dashboard statistics * GET /api/service-orders/stats */ router.get('/stats', async (req: TenantRequest, res: Response) => { try { const stats = await service.getDashboardStats(req.tenantId!); res.json(stats); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); /** * Get a single service order * GET /api/service-orders/:id */ router.get('/:id', async (req: TenantRequest, res: Response) => { try { const order = await service.findById(req.tenantId!, req.params.id); if (!order) { return res.status(404).json({ error: 'Service order not found' }); } res.json(order); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); /** * Get by order number * GET /api/service-orders/number/:orderNumber */ router.get('/number/:orderNumber', async (req: TenantRequest, res: Response) => { try { const order = await service.findByOrderNumber(req.tenantId!, req.params.orderNumber); if (!order) { return res.status(404).json({ error: 'Service order not found' }); } res.json(order); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); /** * Update service order * PATCH /api/service-orders/:id */ router.patch('/:id', async (req: TenantRequest, res: Response) => { try { const order = await service.update(req.tenantId!, req.params.id, req.body); if (!order) { return res.status(404).json({ error: 'Service order not found' }); } res.json(order); } catch (error) { res.status(400).json({ error: (error as Error).message }); } }); /** * Add item to order * POST /api/service-orders/:id/items */ router.post('/:id/items', async (req: TenantRequest, res: Response) => { try { const item = await service.addItem(req.tenantId!, req.params.id, req.body); if (!item) { return res.status(404).json({ error: 'Service order not found' }); } res.status(201).json(item); } catch (error) { res.status(400).json({ error: (error as Error).message }); } }); /** * Get order items * GET /api/service-orders/:id/items */ router.get('/:id/items', async (req: TenantRequest, res: Response) => { try { const items = await service.getItems(req.params.id); res.json(items); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); /** * Update order item * PATCH /api/service-orders/:id/items/:itemId */ router.patch('/:id/items/:itemId', async (req: TenantRequest, res: Response) => { try { const item = await service.updateItem(req.params.itemId, req.body); if (!item) { return res.status(404).json({ error: 'Item not found' }); } res.json(item); } catch (error) { res.status(400).json({ error: (error as Error).message }); } }); /** * Remove order item * DELETE /api/service-orders/:id/items/:itemId */ router.delete('/:id/items/:itemId', async (req: TenantRequest, res: Response) => { try { const success = await service.removeItem(req.params.itemId); if (!success) { return res.status(404).json({ error: 'Item not found' }); } res.status(204).send(); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }); return router; }