# Sesión 2026-04-19 (Parte 2) — Fixes, Roles y Features ## Resumen Sesión enfocada en corregir el sistema de alertas/obligaciones, implementar permisos por rol, y enlazar declaraciones con obligaciones. --- ## 1. Alertas de obligaciones — generación per-contribuyente (#10) **Problema:** `sincronizarAlertasManuales` generaba alertas desde el calendario fiscal estático (catálogo genérico), mostrando obligaciones que no correspondían al contribuyente. **Fix:** Para despachos (`isDespachoTenant`): - Genera alertas desde `obligaciones_contribuyente` del contribuyente seleccionado - Respeta frecuencia, `created_at` y periodos completados - "Todos los RFCs" no genera alertas nuevas, solo muestra las existentes - Alertas legacy (`decl-*`, `pago-*`) eliminadas del despacho **Archivos:** `apps/api/src/services/alertas-manuales.service.ts` --- ## 2. Calendario — colores por status de obligación (#7) **Fix:** `generarEventosDesdeObligaciones` ahora genera tipos diferenciados: - `obligacion-pendiente` (amber) - `obligacion-completada` (green) - `obligacion-atrasada` (red) Frontend: iconos y colores agregados en `tipoIcons` / `tipoColors`. **Archivos:** `apps/api/src/services/calendario-fiscal.service.ts`, `apps/web/app/(dashboard)/calendario/page.tsx` --- ## 3. Editar accesos de clientes (#1) **Backend:** Endpoints `GET/POST /usuarios/:id/accesos` para listar y reemplazar accesos de un cliente. **Frontend:** Botón "Accesos" en la lista de usuarios para clientes. Modal con checkboxes de RFCs. **Archivos:** `apps/api/src/controllers/usuarios.controller.ts`, `apps/api/src/routes/usuarios.routes.ts`, `apps/web/app/(dashboard)/usuarios/page.tsx` --- ## 4. Enlazar declaraciones con obligaciones (#6) **Implementación:** Al subir una declaración: 1. Se matchean los impuestos seleccionados (IVA, ISR, IEPS, etc.) contra las obligaciones del contribuyente por keywords 2. Se marcan como completadas en `obligacion_periodos` 3. Se resuelven las alertas `ob-{id}-{periodo}` correspondientes 4. Frontend invalida queries de alertas y calendario **Mapeo:** IVA→"iva", ISR→"isr", IEPS→"ieps", DIOT→"proveedores de iva", SUELDOS→"sueldos"/"salarios" **Archivos:** `apps/api/src/services/declaraciones.service.ts`, `apps/api/src/controllers/documentos.controller.ts`, `apps/web/lib/api/declaraciones.ts`, `apps/web/lib/hooks/use-declaraciones.ts`, `apps/web/app/(dashboard)/documentos/page.tsx` --- ## 5. Obligaciones — limpieza al desactivar **Fix:** `removeObligacion` ahora elimina alertas (`DELETE FROM alertas WHERE tipo LIKE 'ob-{id}-%'`) y periodos completados al desactivar. `initRecomendaciones` limpia alertas y periodos antes de reemplazar. **Prevención:** `getAlertasManualesPendientes` excluye alertas de obligaciones inactivas (`activa = false`). **Archivos:** `apps/api/src/services/obligaciones.service.ts`, `apps/api/src/services/alertas-manuales.service.ts`, `apps/web/app/(dashboard)/configuracion/obligaciones/page.tsx` --- ## 6. Filtro alertas por rol (auxiliar, supervisor, cliente) **Fix:** `getAlertasManualesPendientes` ahora filtra por rol: - **Owner:** todas las alertas - **Supervisor:** solo de contribuyentes en sus carteras - **Auxiliar:** solo de contribuyentes en sus subcarteras - **Cliente:** solo de contribuyentes en `cliente_accesos` Dashboard (`/dashboard/alertas`) usa `getAlertasManualesPendientes` con filtro por rol en lugar de `dashboardService.getAlertas` sin filtro. **Archivos:** `apps/api/src/services/alertas-manuales.service.ts`, `apps/api/src/controllers/dashboard.controller.ts`, `apps/api/src/controllers/alertas.controller.ts` --- ## 7. Sidebar — roles de despacho **Cambios:** - **Supervisor:** agregado a Pendientes, Dashboard, Reportes, Facturación - **Cliente:** agregado a Dashboard, Reportes - **Carteras:** visible para supervisor y auxiliar - **Onboarding:** oculto para cliente; login redirige directo a dashboard para cliente/auxiliar/supervisor **Archivos:** `apps/web/components/layouts/sidebar.tsx`, `apps/web/app/(auth)/login/page.tsx` --- ## 8. Permisos de carteras — niveles por rol | Acción | Owner | Supervisor | Auxiliar | |---|---|---|---| | Ver carteras | Todas | Sus asignadas | Sus subcarteras | | Crear cartera | Sí | No | No | | Editar/eliminar cartera | Sí | No | No | | Agregar/quitar RFCs a cartera | Sí | No | No | | Crear subcarteras | Sí | Sí | No | | Agregar RFCs a subcarteras | Sí | Sí | No | **Backend:** Lógica de permisos en controller con verificación de parent para subcarteras. **Frontend:** Props `canEdit` y `canManageSubcarteras` condicionan botones. **Archivos:** `apps/api/src/controllers/cartera.controller.ts`, `apps/api/src/routes/cartera.routes.ts`, `apps/web/app/(dashboard)/carteras/page.tsx` --- ## 9. Supervisor — visibilidad de contribuyentes **Problema:** El supervisor veía todos los contribuyentes porque `entidades-visibles.ts` buscaba `supervisor_user_id` (null) y `listContribuyentes([])` devolvía todo. **Fix:** - `entidades-visibles.ts`: supervisor busca en `cartera_entidades` de sus carteras - `listContribuyentes`: array vacío = lista vacía (no todos) **Archivos:** `apps/api/src/utils/entidades-visibles.ts`, `apps/api/src/services/contribuyente.service.ts` --- ## 10. Pendientes — filtro "Mis asignados" **Problema:** Usaba `supervisorUserId` directo (siempre null en despachos). **Fix:** Filtra por `contribuyentes` visibles del usuario actual (ya filtrados por `useContribuyentes` según rol). **Archivos:** `apps/web/app/(dashboard)/pendientes/page.tsx` --- ## 11. Auto-selección de contribuyente **Fix:** Si un usuario solo tiene 1 contribuyente (ej: cliente), se auto-selecciona. No muestra "Todos los RFCs" cuando solo hay 1. **Archivos:** `apps/web/components/contribuyente-selector.tsx` --- ## 12. Conciliación — permisos expandidos **Fix:** Ahora `owner`, `cfo`, `contador`, `auxiliar` y `supervisor` pueden conciliar/desconciliar (antes solo owner+contador). **Archivos:** `apps/api/src/controllers/conciliacion.controller.ts` --- ## 13. Calendario — permisos recordatorios **Fix:** Ahora `owner`, `cfo`, `contador`, `auxiliar` y `supervisor` pueden crear/editar recordatorios (antes solo owner+contador). **Archivos:** `apps/web/app/(dashboard)/calendario/page.tsx` --- ## 14. Dropdown regímenes — posición **Fix:** Dropdown se despliega `left-0` en lugar de `right-0` para evitar desbordamiento. **Archivos:** `packages/shared-ui/src/form/regimen-selector.tsx` --- ## 15. ISR Base Gravable — KPI fallback **Problema:** Al seleccionar un régimen sin datos (605, 621), el KPI mostraba el total global en lugar de $0. **Fix:** `value={regimenSeleccionado ? (bg?.baseGravable ?? 0) : resumenIsr?.baseGravable || 0}` **Archivos:** `apps/web/app/(dashboard)/impuestos/page.tsx` --- ## 16. CFDIs — filtro expandido solo para listado **Problema:** El filtro `OR rfc_emisor/rfc_receptor` se aplicó a todos los servicios, causando doble conteo en métricas fiscales. **Fix:** Filtro expandido solo en `cfdi.service.ts` (listado). Dashboard, Impuestos, Reportes, Alertas, Conciliación usan solo `contribuyente_id`. **Archivos:** `apps/api/src/utils/contribuyente-context.ts`, `apps/api/src/services/dashboard.service.ts`, `apps/api/src/services/alertas-auto.service.ts`, `apps/api/src/services/reportes.service.ts`, `apps/api/src/services/conciliacion.service.ts`, `apps/api/src/controllers/alertas.controller.ts`