Files
HoruxDespachosNuevo/docs/plans/2026-04-19-session-2-fixes-and-features.md

7.3 KiB

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 No No
Editar/eliminar cartera No No
Agregar/quitar RFCs a cartera No No
Crear subcarteras No
Agregar RFCs a subcarteras 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