Initial commit - Horux Despachos NL
This commit is contained in:
11
apps/api/src/routes/admin-addons.routes.ts
Normal file
11
apps/api/src/routes/admin-addons.routes.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import * as ctrl from '../controllers/admin-addons.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
router.use(authenticate);
|
||||
|
||||
router.get('/catalogo', ctrl.listCatalogo);
|
||||
router.put('/catalogo/:id', ctrl.updateCatalogoItem);
|
||||
|
||||
export default router;
|
||||
11
apps/api/src/routes/admin-clientes.routes.ts
Normal file
11
apps/api/src/routes/admin-clientes.routes.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import * as ctrl from '../controllers/admin-clientes.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
router.use(authenticate);
|
||||
|
||||
router.get('/stats', ctrl.getStats);
|
||||
router.get('/:tenantId/usuarios', ctrl.listUsuarios);
|
||||
|
||||
export default router;
|
||||
12
apps/api/src/routes/admin-dashboard.routes.ts
Normal file
12
apps/api/src/routes/admin-dashboard.routes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import * as ctrl from '../controllers/admin-dashboard.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
router.use(authenticate);
|
||||
|
||||
router.get('/metrics', ctrl.getMetrics);
|
||||
router.get('/despachos', ctrl.listDespachos);
|
||||
router.get('/activity', ctrl.getActivity);
|
||||
|
||||
export default router;
|
||||
11
apps/api/src/routes/admin-impersonate.routes.ts
Normal file
11
apps/api/src/routes/admin-impersonate.routes.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import * as ctrl from '../controllers/admin-impersonate.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
router.use(authenticate);
|
||||
|
||||
router.post('/', ctrl.startImpersonation);
|
||||
router.post('/stop', ctrl.stopImpersonation);
|
||||
|
||||
export default router;
|
||||
34
apps/api/src/routes/alertas.routes.ts
Normal file
34
apps/api/src/routes/alertas.routes.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as alertasController from '../controllers/alertas.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/', alertasController.getAlertas);
|
||||
router.get('/automaticas', alertasController.getAlertasAutomaticas);
|
||||
router.get('/manuales', alertasController.getManualesPendientes);
|
||||
router.patch('/manuales/:id/resolver', alertasController.resolverAlertaManual);
|
||||
router.get('/drilldown/lista-negra-clientes', alertasController.getListaNegraClientes);
|
||||
router.get('/drilldown/lista-negra-proveedores', alertasController.getListaNegraProveedores);
|
||||
router.get('/drilldown/concentracion-clientes', alertasController.getConcentracionClientes);
|
||||
router.get('/drilldown/concentracion-proveedores', alertasController.getConcentracionProveedores);
|
||||
router.get('/drilldown/discrepancia-regimen', alertasController.getDiscrepanciaRegimen);
|
||||
router.get('/drilldown/cancelaciones', alertasController.getCancelados);
|
||||
router.get('/drilldown/cancelaciones-periodo-anterior', alertasController.getCancelacionesPeriodoAnterior);
|
||||
router.get('/drilldown/efectivo', alertasController.getEfectivo);
|
||||
router.get('/drilldown/tipo-relacion-sospechosa', alertasController.getTipoRelacionSospechosa);
|
||||
router.post('/descartar', alertasController.descartarCfdis);
|
||||
router.delete('/descartar', alertasController.restaurarDescartados);
|
||||
router.get('/descartados', alertasController.getDescartados);
|
||||
router.get('/stats', alertasController.getStats);
|
||||
router.post('/mark-all-read', alertasController.markAllAsRead);
|
||||
router.get('/:id', alertasController.getAlerta);
|
||||
router.post('/', alertasController.createAlerta);
|
||||
router.patch('/:id', alertasController.updateAlerta);
|
||||
router.delete('/:id', alertasController.deleteAlerta);
|
||||
|
||||
export { router as alertasRoutes };
|
||||
13
apps/api/src/routes/audit-log.routes.ts
Normal file
13
apps/api/src/routes/audit-log.routes.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import * as auditLogController from '../controllers/audit-log.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(authorize('owner', 'cfo'));
|
||||
|
||||
// Solo admin global (verificado dentro del controller)
|
||||
router.get('/', auditLogController.listAuditLog);
|
||||
|
||||
export { router as auditLogRoutes };
|
||||
69
apps/api/src/routes/auth.routes.ts
Normal file
69
apps/api/src/routes/auth.routes.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import * as authController from '../controllers/auth.controller.js';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { strictLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
// Rate limiting: 10 login attempts per 15 minutes per IP
|
||||
const loginLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 10,
|
||||
message: { message: 'Demasiados intentos de login. Intenta de nuevo en 15 minutos.' },
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// Rate limiting: 3 registrations per hour per IP
|
||||
const registerLimiter = rateLimit({
|
||||
windowMs: 60 * 60 * 1000,
|
||||
max: 3,
|
||||
message: { message: 'Demasiados registros. Intenta de nuevo en 1 hora.' },
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// Rate limiting: 20 refresh attempts per 15 minutes per IP
|
||||
const refreshLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 20,
|
||||
message: { message: 'Demasiadas solicitudes. Intenta de nuevo más tarde.' },
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// Rate limiting: 3 password reset requests per hour per IP — evita spam + enumeration
|
||||
const passwordResetRequestLimiter = rateLimit({
|
||||
windowMs: 60 * 60 * 1000,
|
||||
max: 3,
|
||||
message: { message: 'Demasiadas solicitudes de recuperación. Intenta de nuevo en 1 hora.' },
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// Rate limiting: 10 confirm attempts per hour per IP — prevenir brute-force del token
|
||||
const passwordResetConfirmLimiter = rateLimit({
|
||||
windowMs: 60 * 60 * 1000,
|
||||
max: 10,
|
||||
message: { message: 'Demasiados intentos. Intenta de nuevo más tarde.' },
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
router.post('/register', registerLimiter, authController.register);
|
||||
router.post('/login', loginLimiter, authController.login);
|
||||
router.post('/refresh', refreshLimiter, authController.refresh);
|
||||
router.post('/logout', authenticate, authController.logout);
|
||||
router.get('/me', authenticate, authController.me);
|
||||
router.post('/password-reset/request', passwordResetRequestLimiter, authController.requestPasswordReset);
|
||||
router.post('/password-reset/confirm', passwordResetConfirmLimiter, authController.confirmPasswordReset);
|
||||
// 10/hora — prevenir brute-force del currentPassword
|
||||
router.post('/password-change', authenticate, strictLimit, authController.changePassword);
|
||||
router.post('/logout-all', authenticate, authController.logoutAll);
|
||||
router.post('/switch-tenant', authenticate, authController.switchTenant);
|
||||
// Auto-dismiss del onboarding (lo llama el frontend cuando el user completa
|
||||
// los pasos requeridos). Idempotente — múltiples llamadas no rompen.
|
||||
router.post('/onboarding/dismiss', authenticate, authController.dismissOnboarding);
|
||||
|
||||
export { router as authRoutes };
|
||||
16
apps/api/src/routes/bancos.routes.ts
Normal file
16
apps/api/src/routes/bancos.routes.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as bancosController from '../controllers/bancos.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/', bancosController.getBancos);
|
||||
router.post('/', bancosController.createBanco);
|
||||
router.put('/:id', bancosController.updateBanco);
|
||||
router.delete('/:id', bancosController.deleteBanco);
|
||||
|
||||
export { router as bancosRoutes };
|
||||
23
apps/api/src/routes/calendario.routes.ts
Normal file
23
apps/api/src/routes/calendario.routes.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as calendarioController from '../controllers/calendario.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// GET /api/calendario/generados — eventos fiscales + recordatorios custom
|
||||
router.get('/generados', calendarioController.getEventosGenerados);
|
||||
|
||||
// POST /api/calendario — crear recordatorio custom
|
||||
router.post('/', calendarioController.createRecordatorio);
|
||||
|
||||
// PATCH /api/calendario/:id — editar recordatorio custom
|
||||
router.patch('/:id', calendarioController.updateRecordatorio);
|
||||
|
||||
// DELETE /api/calendario/:id — eliminar recordatorio custom
|
||||
router.delete('/:id', calendarioController.deleteRecordatorio);
|
||||
|
||||
export { router as calendarioRoutes };
|
||||
32
apps/api/src/routes/cartera.routes.ts
Normal file
32
apps/api/src/routes/cartera.routes.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/cartera.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// Static routes first
|
||||
router.get('/supervisores', authorize('owner'), ctrl.getSupervisores);
|
||||
|
||||
// Read: owner + supervisor + auxiliar
|
||||
router.get('/', authorize('owner', 'supervisor', 'auxiliar'), ctrl.list);
|
||||
router.get('/:id', authorize('owner', 'supervisor', 'auxiliar'), ctrl.getById);
|
||||
router.get('/:id/subcarteras', authorize('owner', 'supervisor', 'auxiliar'), ctrl.listSubcarteras);
|
||||
router.get('/:id/entidades', authorize('owner', 'supervisor', 'auxiliar'), ctrl.getEntidades);
|
||||
router.get('/:id/auxiliares', authorize('owner', 'supervisor', 'auxiliar'), ctrl.getAuxiliares);
|
||||
router.get('/:supervisorId/auxiliares-disponibles', authorize('owner', 'supervisor'), ctrl.getAuxiliaresDelSupervisor);
|
||||
|
||||
// Write: owner + supervisor (with permission checks in controller)
|
||||
router.post('/', authorize('owner', 'supervisor'), ctrl.create);
|
||||
router.put('/:id', authorize('owner', 'supervisor'), ctrl.update);
|
||||
router.delete('/:id', authorize('owner', 'supervisor'), ctrl.remove);
|
||||
router.post('/:id/subcarteras', authorize('owner', 'supervisor'), ctrl.createSubcartera);
|
||||
router.post('/:id/entidades', authorize('owner', 'supervisor'), ctrl.addEntidad);
|
||||
router.delete('/:id/entidades/:entidadId', authorize('owner', 'supervisor'), ctrl.removeEntidad);
|
||||
router.post('/:id/auxiliares', authorize('owner', 'supervisor'), ctrl.addAuxiliar);
|
||||
router.delete('/:id/auxiliares/:auxiliarUserId', authorize('owner', 'supervisor'), ctrl.removeAuxiliar);
|
||||
|
||||
export default router;
|
||||
21
apps/api/src/routes/catalogos.routes.ts
Normal file
21
apps/api/src/routes/catalogos.routes.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { relaxedLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as catalogosController from '../controllers/catalogos.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(relaxedLimit);
|
||||
|
||||
router.get('/forma-pago', catalogosController.getFormasPago);
|
||||
router.get('/metodo-pago', catalogosController.getMetodosPago);
|
||||
router.get('/uso-cfdi', catalogosController.getUsosCfdi);
|
||||
router.get('/moneda', catalogosController.getMonedas);
|
||||
router.get('/clave-unidad', catalogosController.getClavesUnidad);
|
||||
router.get('/clave-prod-serv', catalogosController.searchClaveProdServ);
|
||||
router.get('/objeto-imp', catalogosController.getObjetosImp);
|
||||
router.get('/tipo-relacion', catalogosController.getTiposRelacion);
|
||||
router.get('/exportacion', catalogosController.getExportaciones);
|
||||
|
||||
export { router as catalogosRoutes };
|
||||
31
apps/api/src/routes/cfdi.routes.ts
Normal file
31
apps/api/src/routes/cfdi.routes.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import express from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { checkPlanLimits, checkCfdiLimit } from '../middlewares/plan-limits.middleware.js';
|
||||
import { strictLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as cfdiController from '../controllers/cfdi.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
router.use(checkPlanLimits);
|
||||
|
||||
router.get('/', cfdiController.getCfdis);
|
||||
router.get('/resumen', cfdiController.getResumen);
|
||||
router.get('/emisores', cfdiController.getEmisores);
|
||||
router.get('/receptores', cfdiController.getReceptores);
|
||||
router.get('/drill-down', cfdiController.drillDown);
|
||||
// Listado de conceptos cross-CFDI (pestaña Conceptos en /cfdi).
|
||||
// Debe registrarse antes que /:id para que Express no lo trate como id.
|
||||
router.get('/conceptos', cfdiController.listConceptos);
|
||||
router.get('/:id', cfdiController.getCfdiById);
|
||||
router.get('/:id/conceptos', cfdiController.getConceptos);
|
||||
router.get('/:id/xml', cfdiController.getXml);
|
||||
router.post('/', checkCfdiLimit, cfdiController.createCfdi);
|
||||
// Bulk upload: 10/hora — procesa hasta 50MB, pesado en parseo + inserts
|
||||
router.post('/bulk', strictLimit, express.json({ limit: '50mb' }), checkCfdiLimit, cfdiController.createManyCfdis);
|
||||
router.delete('/:id', cfdiController.deleteCfdi);
|
||||
|
||||
export { router as cfdiRoutes };
|
||||
17
apps/api/src/routes/conciliacion.routes.ts
Normal file
17
apps/api/src/routes/conciliacion.routes.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { requireFeature } from '../middlewares/feature-gate.middleware.js';
|
||||
import * as conciliacionController from '../controllers/conciliacion.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
router.use(requireFeature('conciliacion'));
|
||||
|
||||
router.get('/', conciliacionController.getCfdis);
|
||||
router.post('/', conciliacionController.conciliar);
|
||||
router.delete('/:id', conciliacionController.desconciliar);
|
||||
|
||||
export { router as conciliacionRoutes };
|
||||
15
apps/api/src/routes/connector.routes.ts
Normal file
15
apps/api/src/routes/connector.routes.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/connector.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
// Public endpoint — called by connector Docker container (no user JWT, uses HORUX_TOKEN)
|
||||
router.post('/heartbeat', ctrl.heartbeat);
|
||||
|
||||
// Authenticated endpoints — for tenant owners managing their connector
|
||||
router.get('/status', authenticate, tenantMiddleware, ctrl.status);
|
||||
router.post('/provision', authenticate, tenantMiddleware, authorize('owner', 'cfo'), ctrl.provision);
|
||||
|
||||
export default router;
|
||||
47
apps/api/src/routes/contribuyente.routes.ts
Normal file
47
apps/api/src/routes/contribuyente.routes.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/contribuyente.controller.js';
|
||||
import * as configCtrl from '../controllers/contribuyente-config.controller.js';
|
||||
import * as obligacionesCtrl from '../controllers/obligaciones.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// === Static routes FIRST (before /:id to avoid route conflict) ===
|
||||
router.get('/', ctrl.list);
|
||||
router.post('/', authorize('owner', 'cfo'), ctrl.create);
|
||||
router.post('/backfill', authorize('owner'), ctrl.backfill);
|
||||
router.get('/catalogo-obligaciones', obligacionesCtrl.getCatalogo);
|
||||
|
||||
// === Dynamic routes with :id ===
|
||||
router.get('/:id', ctrl.getById);
|
||||
router.put('/:id', authorize('owner', 'cfo'), ctrl.update);
|
||||
router.delete('/:id', authorize('owner'), ctrl.deactivate);
|
||||
router.post('/:id/cliente-acceso', authorize('owner', 'supervisor'), ctrl.addClienteAcceso);
|
||||
|
||||
// FIEL per contribuyente
|
||||
router.post('/:id/fiel', authorize('owner', 'cfo'), configCtrl.uploadFiel);
|
||||
router.get('/:id/fiel/status', configCtrl.fielStatus);
|
||||
router.delete('/:id/fiel', authorize('owner', 'cfo'), configCtrl.deleteFiel);
|
||||
|
||||
// Facturapi per contribuyente
|
||||
router.post('/:id/facturapi/org', authorize('owner', 'cfo'), configCtrl.createOrg);
|
||||
router.get('/:id/facturapi/status', configCtrl.orgStatus);
|
||||
router.post('/:id/facturapi/csd', authorize('owner', 'cfo'), configCtrl.uploadCsd);
|
||||
|
||||
// Obligaciones fiscales per contribuyente
|
||||
router.get('/:id/obligaciones/periodo', obligacionesCtrl.getObligacionesPorPeriodo);
|
||||
router.get('/:id/obligaciones', obligacionesCtrl.getObligaciones);
|
||||
router.post('/:id/obligaciones/init', authorize('owner', 'cfo'), obligacionesCtrl.initRecomendaciones);
|
||||
router.post('/:id/obligaciones', authorize('owner', 'cfo'), obligacionesCtrl.addObligacion);
|
||||
router.delete('/:id/obligaciones/:obligacionId', authorize('owner', 'cfo'), obligacionesCtrl.removeObligacion);
|
||||
router.post('/:id/obligaciones/:obligacionId/restore', authorize('owner', 'cfo'), obligacionesCtrl.restoreObligacion);
|
||||
router.post('/:id/obligaciones/:obligacionId/complete', authorize('owner', 'cfo', 'contador', 'auxiliar'), obligacionesCtrl.completeObligacion);
|
||||
router.post('/:id/obligaciones/:obligacionId/uncomplete', authorize('owner', 'cfo', 'contador', 'auxiliar'), obligacionesCtrl.uncompleteObligacion);
|
||||
router.post('/:id/obligaciones/:obligacionId/complete-periodo', authorize('owner', 'cfo', 'contador', 'auxiliar'), obligacionesCtrl.completePeriodo);
|
||||
router.post('/:id/obligaciones/:obligacionId/uncomplete-periodo', authorize('owner', 'cfo', 'contador', 'auxiliar'), obligacionesCtrl.uncompletePeriodo);
|
||||
|
||||
export default router;
|
||||
20
apps/api/src/routes/dashboard.routes.ts
Normal file
20
apps/api/src/routes/dashboard.routes.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { checkPlanLimits } from '../middlewares/plan-limits.middleware.js';
|
||||
import { normalLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as dashboardController from '../controllers/dashboard.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(normalLimit);
|
||||
router.use(tenantMiddleware);
|
||||
router.use(checkPlanLimits);
|
||||
|
||||
router.get('/kpis', dashboardController.getKpis);
|
||||
router.get('/ingresos-egresos', dashboardController.getIngresosEgresos);
|
||||
router.get('/regimenes-periodo', dashboardController.getRegimenesDelPeriodo);
|
||||
router.get('/alertas', dashboardController.getAlertas);
|
||||
|
||||
export { router as dashboardRoutes };
|
||||
12
apps/api/src/routes/despacho-audit.routes.ts
Normal file
12
apps/api/src/routes/despacho-audit.routes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/despacho-audit.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/', ctrl.getDespachoAuditLog);
|
||||
|
||||
export default router;
|
||||
15
apps/api/src/routes/despacho-stats.routes.ts
Normal file
15
apps/api/src/routes/despacho-stats.routes.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/despacho-stats.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/contribuyentes-stats', ctrl.getContribuyentesStats);
|
||||
router.get('/mis-asignados', ctrl.getMisAsignados);
|
||||
router.get('/equipo-stats', ctrl.getEquipoStats);
|
||||
|
||||
export { router as despachoStatsRoutes };
|
||||
17
apps/api/src/routes/despacho.routes.ts
Normal file
17
apps/api/src/routes/despacho.routes.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { signup, getMyPlan } from '../controllers/despacho.controller.js';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
const signupLimiter = rateLimit({
|
||||
windowMs: 60 * 60 * 1000,
|
||||
max: 5,
|
||||
message: { message: 'Demasiados intentos de registro. Intenta en una hora.' },
|
||||
});
|
||||
|
||||
router.post('/signup', signupLimiter, signup);
|
||||
router.get('/me/plan', authenticate, getMyPlan);
|
||||
|
||||
export default router;
|
||||
38
apps/api/src/routes/documentos.routes.ts
Normal file
38
apps/api/src/routes/documentos.routes.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { requireFeature } from '../middlewares/feature-gate.middleware.js';
|
||||
import { veryStrictLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as documentosController from '../controllers/documentos.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
router.use(requireFeature('documentos'));
|
||||
|
||||
router.get('/opiniones', documentosController.listarOpiniones);
|
||||
router.get('/opiniones/:id/pdf', documentosController.descargarPdf);
|
||||
// 2/día — Playwright headless contra portal SAT es caro
|
||||
router.post('/opiniones/consultar', veryStrictLimit, authorize('owner', 'cfo'), documentosController.consultarManual);
|
||||
|
||||
// Constancia de Situación Fiscal
|
||||
router.get('/constancias', documentosController.listarConstancias);
|
||||
router.get('/constancias/:id/pdf', documentosController.descargarConstanciaPdf);
|
||||
router.post('/constancias/consultar', veryStrictLimit, authorize('owner', 'cfo'), documentosController.consultarConstanciaManual);
|
||||
|
||||
// Declaraciones provisionales
|
||||
router.get('/declaraciones', documentosController.listarDeclaraciones);
|
||||
router.post('/declaraciones', documentosController.crearDeclaracion);
|
||||
router.post('/declaraciones/:id/comprobante-pago', documentosController.subirComprobantePago);
|
||||
router.get('/declaraciones/:id/pdf/:variant', documentosController.descargarDeclaracionPdf);
|
||||
router.delete('/declaraciones/:id', documentosController.eliminarDeclaracion);
|
||||
|
||||
// Extras (PDFs libres)
|
||||
router.get('/extras', documentosController.listarExtras);
|
||||
router.get('/extras/categorias', documentosController.listarCategoriasExtras);
|
||||
router.post('/extras', documentosController.crearExtra);
|
||||
router.get('/extras/:id/pdf', documentosController.descargarExtraPdf);
|
||||
router.delete('/extras/:id', documentosController.eliminarExtra);
|
||||
|
||||
export { router as documentosRoutes };
|
||||
14
apps/api/src/routes/export.routes.ts
Normal file
14
apps/api/src/routes/export.routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as exportController from '../controllers/export.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/cfdis', exportController.exportCfdis);
|
||||
router.get('/reporte', exportController.exportReporte);
|
||||
|
||||
export { router as exportRoutes };
|
||||
64
apps/api/src/routes/facturacion.routes.ts
Normal file
64
apps/api/src/routes/facturacion.routes.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { strictLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as facturacionController from '../controllers/facturacion.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// Organización Facturapi
|
||||
router.get('/org/status', facturacionController.getOrgStatus);
|
||||
router.post('/org', authorize('owner', 'cfo'), facturacionController.createOrg);
|
||||
|
||||
// CSD
|
||||
router.post('/csd', authorize('owner', 'cfo'), facturacionController.uploadCsd);
|
||||
|
||||
// Estado LCO — banner "CSD en proceso de validación" si hubo rechazo del SAT en últimas 24h
|
||||
router.get('/lco-status', facturacionController.getLcoStatus);
|
||||
|
||||
// Emisión y cancelación (admin + contador). 10/hora — cada emisión quema timbre + side-effect en Facturapi/SAT
|
||||
router.post('/emitir', strictLimit, facturacionController.emitir);
|
||||
router.post('/cancelar/:uuid', strictLimit, facturacionController.cancelar);
|
||||
|
||||
// Descargas
|
||||
router.get('/pdf/:id', facturacionController.downloadPdf);
|
||||
router.get('/xml/:id', facturacionController.downloadXml);
|
||||
|
||||
// Timbres
|
||||
router.get('/timbres', facturacionController.getTimbres);
|
||||
router.get('/timbres/paquetes-catalogo', facturacionController.getPaquetesCatalogo);
|
||||
// 10/h — cada compra crea MP Preference (side-effect en tercero)
|
||||
router.post('/timbres/paquetes/comprar', strictLimit, facturacionController.comprarPaquete);
|
||||
// Admin global: catálogo completo + editar precios
|
||||
router.get('/timbres/paquetes-catalogo/admin', facturacionController.getPaquetesCatalogoAdmin);
|
||||
router.put('/timbres/paquetes-catalogo/:id', facturacionController.updatePaqueteCatalogo);
|
||||
|
||||
// Personalización (logo, color)
|
||||
router.get('/customization', facturacionController.getCustomization);
|
||||
router.post('/logo', facturacionController.uploadLogo);
|
||||
router.put('/color', facturacionController.updateColor);
|
||||
|
||||
// Datos fiscales del tenant
|
||||
router.get('/datos-fiscales', facturacionController.getDatosFiscales);
|
||||
router.put('/datos-fiscales', facturacionController.updateDatosFiscales);
|
||||
|
||||
// Preferencias de auto-facturación de pagos de suscripción (Fase 2)
|
||||
router.get('/preferencias-facturacion', facturacionController.getPreferenciasFacturacion);
|
||||
router.put('/preferencias-facturacion', facturacionController.updatePreferenciasFacturacion);
|
||||
|
||||
// Búsqueda de RFCs para autocompletar
|
||||
router.get('/rfcs/search', facturacionController.searchRfcs);
|
||||
|
||||
// Búsqueda de conceptos previos
|
||||
router.get('/conceptos/search', facturacionController.searchConceptos);
|
||||
|
||||
// CFDIs PPD pendientes de pago por RFC
|
||||
router.get('/cfdis-ppd', facturacionController.getCfdisPpdPendientes);
|
||||
|
||||
// CFDIs emitidos por el contribuyente al receptor (para sección "CFDIs relacionados")
|
||||
router.get('/cfdis-relacionables', facturacionController.getCfdisRelacionables);
|
||||
|
||||
export { router as facturacionRoutes };
|
||||
20
apps/api/src/routes/fiel.routes.ts
Normal file
20
apps/api/src/routes/fiel.routes.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import * as fielController from '../controllers/fiel.controller.js';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// POST /api/fiel/upload - Subir credenciales FIEL
|
||||
router.post('/upload', fielController.upload);
|
||||
|
||||
// GET /api/fiel/status - Obtener estado de la FIEL
|
||||
router.get('/status', fielController.status);
|
||||
|
||||
// DELETE /api/fiel - Eliminar credenciales FIEL
|
||||
router.delete('/', fielController.remove);
|
||||
|
||||
export default router;
|
||||
30
apps/api/src/routes/impuestos.routes.ts
Normal file
30
apps/api/src/routes/impuestos.routes.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { normalLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as impuestosController from '../controllers/impuestos.controller.js';
|
||||
import * as activosFijosController from '../controllers/activos-fijos.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(normalLimit);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/iva/mensual', impuestosController.getIvaMensual);
|
||||
router.get('/iva/resumen', impuestosController.getResumenIva);
|
||||
router.get('/isr/mensual', impuestosController.getIsrMensual);
|
||||
router.get('/isr/resumen', impuestosController.getResumenIsr);
|
||||
router.get('/isr/resumen-desglosado', impuestosController.getResumenIsrDesglosado);
|
||||
router.get('/isr/coeficiente', impuestosController.getCoeficiente);
|
||||
router.put('/isr/coeficiente', impuestosController.setCoeficiente);
|
||||
|
||||
// Activos fijos: vista informativa de deducción mensual proporcional.
|
||||
// NO afecta gastos ni ISR — el SAT y el dashboard tratan estos CFDIs
|
||||
// como gasto del periodo (igual que antes).
|
||||
router.get('/activos-fijos', activosFijosController.list);
|
||||
router.put('/activos-fijos/usos-excluidos', activosFijosController.setUsosExcluidos);
|
||||
router.post('/activos-fijos/:cfdiId/baja', activosFijosController.darDeBaja);
|
||||
router.delete('/activos-fijos/:cfdiId/baja', activosFijosController.revertirBaja);
|
||||
|
||||
export { router as impuestosRoutes };
|
||||
12
apps/api/src/routes/metricas.routes.ts
Normal file
12
apps/api/src/routes/metricas.routes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/metricas.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/mensuales', ctrl.getMensuales);
|
||||
|
||||
export default router;
|
||||
14
apps/api/src/routes/notification-preferences.routes.ts
Normal file
14
apps/api/src/routes/notification-preferences.routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/notification-preferences.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/', ctrl.listPreferences);
|
||||
router.put('/', ctrl.updatePreferences);
|
||||
|
||||
export { router as notificationPreferencesRoutes };
|
||||
18
apps/api/src/routes/papeleria.routes.ts
Normal file
18
apps/api/src/routes/papeleria.routes.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/papeleria.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/', ctrl.list);
|
||||
router.post('/', ctrl.upload);
|
||||
router.get('/:id/download', ctrl.download);
|
||||
router.post('/:id/aprobar', ctrl.aprobar);
|
||||
router.post('/:id/rechazar', ctrl.rechazar);
|
||||
router.delete('/:id', ctrl.eliminar);
|
||||
|
||||
export { router as papeleriaRoutes };
|
||||
17
apps/api/src/routes/plan-catalogo.routes.ts
Normal file
17
apps/api/src/routes/plan-catalogo.routes.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import * as ctrl from '../controllers/plan-catalogo.controller.js';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
// Public endpoints — no auth needed (pricing page)
|
||||
router.get('/', ctrl.getPlans);
|
||||
router.get('/addons', ctrl.getAddons);
|
||||
|
||||
// Catálogo despacho — admin only (require auth)
|
||||
router.get('/despacho', authenticate, ctrl.listDespachoCatalogo);
|
||||
router.patch('/despacho/:plan', authenticate, ctrl.updateDespachoCatalogo);
|
||||
|
||||
router.get('/:codename', ctrl.getPlan);
|
||||
|
||||
export default router;
|
||||
16
apps/api/src/routes/platform-staff.routes.ts
Normal file
16
apps/api/src/routes/platform-staff.routes.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import * as platformStaffController from '../controllers/platform-staff.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(authorize('owner', 'cfo'));
|
||||
|
||||
// Solo platform_admin (verificado dentro del controller)
|
||||
router.get('/', platformStaffController.listStaff);
|
||||
router.get('/search', platformStaffController.searchUsers);
|
||||
router.post('/grant', platformStaffController.grantRole);
|
||||
router.post('/revoke', platformStaffController.revokeRole);
|
||||
|
||||
export { router as platformStaffRoutes };
|
||||
28
apps/api/src/routes/regimen.routes.ts
Normal file
28
apps/api/src/routes/regimen.routes.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { relaxedLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as regimenController from '../controllers/regimen.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(relaxedLimit);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// GET /api/regimenes — catálogo completo
|
||||
router.get('/', regimenController.getAllRegimenes);
|
||||
|
||||
// GET /api/regimenes/activos — regímenes activos del tenant
|
||||
router.get('/activos', regimenController.getActivos);
|
||||
|
||||
// PUT /api/regimenes/activos — configurar regímenes activos
|
||||
router.put('/activos', regimenController.setActivos);
|
||||
|
||||
// GET /api/regimenes/ignorados — regímenes ignorados del tenant actual
|
||||
router.get('/ignorados', regimenController.getIgnorados);
|
||||
|
||||
// PUT /api/regimenes/ignorados — configurar regímenes ignorados
|
||||
router.put('/ignorados', regimenController.setIgnorados);
|
||||
|
||||
export { router as regimenRoutes };
|
||||
24
apps/api/src/routes/reportes.routes.ts
Normal file
24
apps/api/src/routes/reportes.routes.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { checkPlanLimits } from '../middlewares/plan-limits.middleware.js';
|
||||
import { requireFeature } from '../middlewares/feature-gate.middleware.js';
|
||||
import { normalLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as reportesController from '../controllers/reportes.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(normalLimit);
|
||||
router.use(tenantMiddleware);
|
||||
router.use(checkPlanLimits);
|
||||
router.use(requireFeature('reportes'));
|
||||
|
||||
router.get('/estado-resultados', reportesController.getEstadoResultados);
|
||||
router.get('/flujo-efectivo', reportesController.getFlujoEfectivo);
|
||||
router.get('/comparativo', reportesController.getComparativo);
|
||||
router.get('/concentrado-rfc', reportesController.getConcentradoRfc);
|
||||
router.get('/cuentas-x-pagar', reportesController.getCuentasXPagar);
|
||||
router.get('/cuentas-x-cobrar', reportesController.getCuentasXCobrar);
|
||||
|
||||
export { router as reportesRoutes };
|
||||
31
apps/api/src/routes/sat.routes.ts
Normal file
31
apps/api/src/routes/sat.routes.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import * as satController from '../controllers/sat.controller.js';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import { veryStrictLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
// POST /api/sat/sync - Iniciar sincronización manual (2/día por user, admin global exento)
|
||||
router.post('/sync', veryStrictLimit, satController.start);
|
||||
|
||||
// GET /api/sat/sync/status - Estado actual de sincronización
|
||||
router.get('/sync/status', satController.status);
|
||||
|
||||
// GET /api/sat/sync/history - Historial de sincronizaciones
|
||||
router.get('/sync/history', satController.history);
|
||||
|
||||
// GET /api/sat/sync/:id - Detalle de un job
|
||||
router.get('/sync/:id', satController.jobDetail);
|
||||
|
||||
// POST /api/sat/sync/:id/retry - Reintentar job fallido
|
||||
router.post('/sync/:id/retry', satController.retry);
|
||||
|
||||
// Admin-only cron endpoints (global admin verified in controller)
|
||||
router.get('/cron', authorize('owner', 'cfo'), satController.cronInfo);
|
||||
router.post('/cron/run', authorize('owner', 'cfo'), satController.runCron);
|
||||
|
||||
export default router;
|
||||
37
apps/api/src/routes/subscription.routes.ts
Normal file
37
apps/api/src/routes/subscription.routes.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate, authorize } from '../middlewares/auth.middleware.js';
|
||||
import { strictLimit } from '../middlewares/rate-limit.middleware.js';
|
||||
import * as subscriptionController from '../controllers/subscription.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
// All endpoints require authentication + admin role
|
||||
router.use(authenticate);
|
||||
router.use(authorize('owner', 'cfo'));
|
||||
|
||||
// (Endpoints /plans y /plans/:id eliminados con el modelo PlanPrice legacy.
|
||||
// Para precios despacho usa /api/planes/despacho.)
|
||||
|
||||
// Self-serve: el usuario actúa sobre el tenant de su JWT
|
||||
router.post('/me/trial', subscriptionController.startMyTrial);
|
||||
// 10/hora — crea preapprovals/preferences en MercadoPago (side-effect en tercero)
|
||||
router.post('/me/subscribe', strictLimit, subscriptionController.subscribeMe);
|
||||
router.post('/me/change', strictLimit, subscriptionController.changeMyPlan);
|
||||
router.post('/me/upgrade', strictLimit, subscriptionController.upgradeMe);
|
||||
router.post('/me/upgrade/cancel', subscriptionController.cancelMyPendingUpgrade);
|
||||
router.post('/me/cancel', subscriptionController.cancelMySubscription);
|
||||
router.post('/me/reactivate', subscriptionController.reactivateMe);
|
||||
router.get('/me/addons', subscriptionController.getMyAddons);
|
||||
router.post('/me/addons', strictLimit, subscriptionController.addMyAddon);
|
||||
router.delete('/me/addons/:addonId', subscriptionController.cancelMyAddon);
|
||||
|
||||
// Listar todas las suscripciones (global admin)
|
||||
router.get('/', subscriptionController.getAllSubscriptions);
|
||||
|
||||
// Admin subscription management (global admin verified in controller)
|
||||
router.get('/:tenantId', subscriptionController.getSubscription);
|
||||
router.post('/:tenantId/generate-link', subscriptionController.generatePaymentLink);
|
||||
router.post('/:tenantId/mark-paid', subscriptionController.markAsPaid);
|
||||
router.get('/:tenantId/payments', subscriptionController.getPayments);
|
||||
|
||||
export { router as subscriptionRoutes };
|
||||
20
apps/api/src/routes/tareas.routes.ts
Normal file
20
apps/api/src/routes/tareas.routes.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as ctrl from '../controllers/tareas.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
router.use(tenantMiddleware);
|
||||
|
||||
router.get('/', ctrl.listTareas);
|
||||
router.post('/', ctrl.createTarea);
|
||||
router.post('/seed', ctrl.seedDefaults);
|
||||
router.patch('/:id', ctrl.updateTarea);
|
||||
router.delete('/:id', ctrl.deleteTarea);
|
||||
|
||||
router.post('/periodo/:id/completar', ctrl.completarPeriodo);
|
||||
router.delete('/periodo/:id/completar', ctrl.descompletarPeriodo);
|
||||
|
||||
export { router as tareasRoutes };
|
||||
20
apps/api/src/routes/tenants.routes.ts
Normal file
20
apps/api/src/routes/tenants.routes.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import * as tenantsController from '../controllers/tenants.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
|
||||
// Self-serve multi-tenant (el caller actúa sobre sus propias memberships)
|
||||
router.get('/mine', tenantsController.getMyTenants);
|
||||
router.post('/mine', tenantsController.addMyTenant);
|
||||
|
||||
// Admin global
|
||||
router.get('/', tenantsController.getAllTenants);
|
||||
router.get('/:id', tenantsController.getTenant);
|
||||
router.post('/', tenantsController.createTenant);
|
||||
router.put('/:id', tenantsController.updateTenant);
|
||||
router.delete('/:id', tenantsController.deleteTenant);
|
||||
|
||||
export { router as tenantsRoutes };
|
||||
29
apps/api/src/routes/usuarios.routes.ts
Normal file
29
apps/api/src/routes/usuarios.routes.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { authenticate } from '../middlewares/auth.middleware.js';
|
||||
import { tenantMiddleware } from '../middlewares/tenant.middleware.js';
|
||||
import * as usuariosController from '../controllers/usuarios.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
router.use(authenticate);
|
||||
|
||||
// Rutas por tenant
|
||||
router.get('/', usuariosController.getUsuarios);
|
||||
router.post('/invite', usuariosController.inviteUsuario);
|
||||
router.patch('/:id', usuariosController.updateUsuario);
|
||||
router.delete('/:id', usuariosController.deleteUsuario);
|
||||
|
||||
// Cliente accesos (requires tenantPool)
|
||||
router.get('/:id/accesos', tenantMiddleware, usuariosController.getClienteAccesos);
|
||||
router.post('/:id/accesos', tenantMiddleware, usuariosController.setClienteAccesos);
|
||||
|
||||
// Supervisor de auxiliar (requires tenantPool)
|
||||
router.get('/:id/supervisor', tenantMiddleware, usuariosController.getSupervisor);
|
||||
router.put('/:id/supervisor', tenantMiddleware, usuariosController.updateSupervisor);
|
||||
|
||||
// Rutas globales (solo admin global)
|
||||
router.get('/global/all', usuariosController.getAllUsuarios);
|
||||
router.patch('/global/:id', usuariosController.updateUsuarioGlobal);
|
||||
router.delete('/global/:id', usuariosController.deleteUsuarioGlobal);
|
||||
|
||||
export { router as usuariosRoutes };
|
||||
9
apps/api/src/routes/webhook.routes.ts
Normal file
9
apps/api/src/routes/webhook.routes.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Router, type IRouter } from 'express';
|
||||
import { handleMercadoPagoWebhook } from '../controllers/webhook.controller.js';
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
// Public endpoint — no auth middleware
|
||||
router.post('/mercadopago', handleMercadoPagoWebhook);
|
||||
|
||||
export { router as webhookRoutes };
|
||||
Reference in New Issue
Block a user