/** * Fraccionamiento Controller * API endpoints para gestión de fraccionamientos/obras * * @module Construction * @prefix /api/v1/fraccionamientos */ import { Router, Request, Response, NextFunction } from 'express'; import { FraccionamientoService, CreateFraccionamientoDto, UpdateFraccionamientoDto } from '../services/fraccionamiento.service'; const router = Router(); const fraccionamientoService = new FraccionamientoService(); /** * GET /api/v1/fraccionamientos * Lista todos los fraccionamientos del tenant */ router.get('/', async (req: Request, res: Response, next: NextFunction) => { try { const tenantId = req.headers['x-tenant-id'] as string; if (!tenantId) { return res.status(400).json({ error: 'X-Tenant-Id header required' }); } const { proyectoId, estado } = req.query; const fraccionamientos = await fraccionamientoService.findAll({ tenantId, proyectoId: proyectoId as string, estado: estado as any, }); return res.json({ success: true, data: fraccionamientos, count: fraccionamientos.length, }); } catch (error) { return next(error); } }); /** * GET /api/v1/fraccionamientos/:id * Obtiene un fraccionamiento por ID */ router.get('/:id', async (req: Request, res: Response, next: NextFunction) => { try { const tenantId = req.headers['x-tenant-id'] as string; if (!tenantId) { return res.status(400).json({ error: 'X-Tenant-Id header required' }); } const fraccionamiento = await fraccionamientoService.findById(req.params.id, tenantId); if (!fraccionamiento) { return res.status(404).json({ error: 'Fraccionamiento no encontrado' }); } return res.json({ success: true, data: fraccionamiento }); } catch (error) { return next(error); } }); /** * POST /api/v1/fraccionamientos * Crea un nuevo fraccionamiento */ router.post('/', async (req: Request, res: Response, next: NextFunction) => { try { const tenantId = req.headers['x-tenant-id'] as string; if (!tenantId) { return res.status(400).json({ error: 'X-Tenant-Id header required' }); } const data: CreateFraccionamientoDto = { ...req.body, tenantId, createdById: (req as any).user?.id, }; // Validate required fields if (!data.codigo || !data.nombre || !data.proyectoId) { return res.status(400).json({ error: 'codigo, nombre y proyectoId son requeridos' }); } // Check if codigo already exists const existing = await fraccionamientoService.findByCodigo(data.codigo, tenantId); if (existing) { return res.status(409).json({ error: 'Ya existe un fraccionamiento con ese código' }); } const fraccionamiento = await fraccionamientoService.create(data); return res.status(201).json({ success: true, data: fraccionamiento }); } catch (error) { return next(error); } }); /** * PATCH /api/v1/fraccionamientos/:id * Actualiza un fraccionamiento */ router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => { try { const tenantId = req.headers['x-tenant-id'] as string; if (!tenantId) { return res.status(400).json({ error: 'X-Tenant-Id header required' }); } const data: UpdateFraccionamientoDto = req.body; const fraccionamiento = await fraccionamientoService.update( req.params.id, tenantId, data ); if (!fraccionamiento) { return res.status(404).json({ error: 'Fraccionamiento no encontrado' }); } return res.json({ success: true, data: fraccionamiento }); } catch (error) { return next(error); } }); /** * DELETE /api/v1/fraccionamientos/:id * Elimina un fraccionamiento */ router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => { try { const tenantId = req.headers['x-tenant-id'] as string; if (!tenantId) { return res.status(400).json({ error: 'X-Tenant-Id header required' }); } const deleted = await fraccionamientoService.delete(req.params.id, tenantId); if (!deleted) { return res.status(404).json({ error: 'Fraccionamiento no encontrado' }); } return res.json({ success: true, message: 'Fraccionamiento eliminado' }); } catch (error) { return next(error); } }); export default router;