# 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`
