"use strict"; /** * ConceptoController - Controller de conceptos de obra * * Endpoints REST para gestión del catálogo de conceptos. * * @module Budgets */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createConceptoController = createConceptoController; const express_1 = require("express"); const concepto_service_1 = require("../services/concepto.service"); const auth_middleware_1 = require("../../auth/middleware/auth.middleware"); const auth_service_1 = require("../../auth/services/auth.service"); const concepto_entity_1 = require("../entities/concepto.entity"); const user_entity_1 = require("../../core/entities/user.entity"); const tenant_entity_1 = require("../../core/entities/tenant.entity"); const refresh_token_entity_1 = require("../../auth/entities/refresh-token.entity"); /** * Crear router de conceptos */ function createConceptoController(dataSource) { const router = (0, express_1.Router)(); // Repositorios const conceptoRepository = dataSource.getRepository(concepto_entity_1.Concepto); const userRepository = dataSource.getRepository(user_entity_1.User); const tenantRepository = dataSource.getRepository(tenant_entity_1.Tenant); const refreshTokenRepository = dataSource.getRepository(refresh_token_entity_1.RefreshToken); // Servicios const conceptoService = new concepto_service_1.ConceptoService(conceptoRepository); const authService = new auth_service_1.AuthService(userRepository, tenantRepository, refreshTokenRepository); const authMiddleware = new auth_middleware_1.AuthMiddleware(authService, dataSource); // Helper para crear contexto de servicio const getContext = (req) => { if (!req.tenantId) { throw new Error('Tenant ID is required'); } return { tenantId: req.tenantId, userId: req.user?.sub, }; }; /** * GET /conceptos * Listar conceptos raíz */ router.get('/', authMiddleware.authenticate, async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const page = parseInt(req.query.page) || 1; const limit = Math.min(parseInt(req.query.limit) || 50, 100); const result = await conceptoService.findRootConceptos(getContext(req), page, limit); res.status(200).json({ success: true, data: result.data, pagination: result.meta, }); } catch (error) { next(error); } }); /** * GET /conceptos/search * Buscar conceptos por código o nombre */ router.get('/search', authMiddleware.authenticate, async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const term = req.query.q; if (!term || term.length < 2) { res.status(400).json({ error: 'Bad Request', message: 'Search term must be at least 2 characters' }); return; } const limit = Math.min(parseInt(req.query.limit) || 20, 50); const conceptos = await conceptoService.search(getContext(req), term, limit); res.status(200).json({ success: true, data: conceptos }); } catch (error) { next(error); } }); /** * GET /conceptos/tree * Obtener árbol de conceptos */ router.get('/tree', authMiddleware.authenticate, async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const rootId = req.query.rootId; const tree = await conceptoService.getConceptoTree(getContext(req), rootId); res.status(200).json({ success: true, data: tree }); } catch (error) { next(error); } }); /** * GET /conceptos/:id * Obtener concepto por ID */ router.get('/:id', authMiddleware.authenticate, async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const concepto = await conceptoService.findById(getContext(req), req.params.id); if (!concepto) { res.status(404).json({ error: 'Not Found', message: 'Concept not found' }); return; } res.status(200).json({ success: true, data: concepto }); } catch (error) { next(error); } }); /** * GET /conceptos/:id/children * Obtener hijos de un concepto */ router.get('/:id/children', authMiddleware.authenticate, async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const children = await conceptoService.findChildren(getContext(req), req.params.id); res.status(200).json({ success: true, data: children }); } catch (error) { next(error); } }); /** * POST /conceptos * Crear concepto */ router.post('/', authMiddleware.authenticate, authMiddleware.authorize('admin', 'engineer', 'director'), async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const dto = req.body; if (!dto.code || !dto.name) { res.status(400).json({ error: 'Bad Request', message: 'code and name are required' }); return; } // Verificar código único const exists = await conceptoService.codeExists(getContext(req), dto.code); if (exists) { res.status(409).json({ error: 'Conflict', message: 'Concept code already exists' }); return; } const concepto = await conceptoService.createConcepto(getContext(req), dto); res.status(201).json({ success: true, data: concepto }); } catch (error) { next(error); } }); /** * PATCH /conceptos/:id * Actualizar concepto */ router.patch('/:id', authMiddleware.authenticate, authMiddleware.authorize('admin', 'engineer', 'director'), async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const dto = req.body; const concepto = await conceptoService.update(getContext(req), req.params.id, dto); if (!concepto) { res.status(404).json({ error: 'Not Found', message: 'Concept not found' }); return; } res.status(200).json({ success: true, data: concepto }); } catch (error) { next(error); } }); /** * DELETE /conceptos/:id * Eliminar concepto (soft delete) */ router.delete('/:id', authMiddleware.authenticate, authMiddleware.authorize('admin', 'director'), async (req, res, next) => { try { const tenantId = req.tenantId; if (!tenantId) { res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' }); return; } const deleted = await conceptoService.softDelete(getContext(req), req.params.id); if (!deleted) { res.status(404).json({ error: 'Not Found', message: 'Concept not found' }); return; } res.status(200).json({ success: true, message: 'Concept deleted' }); } catch (error) { next(error); } }); return router; } exports.default = createConceptoController; //# sourceMappingURL=concepto.controller.js.map