# Sesión 2026-05-23: Asignaciones, Tareas, Admin UI y Fixes

## Resumen

Sesión extensa con múltiples fixes de bugs críticos descubiertos tras deploy de la feature de asignaciones, más nuevas funcionalidades de UX solicitadas por el usuario.

---

## 1. Fixes de build y deploy inicial de Asignaciones

### Problemas de build de Next.js
- **`Badge` no exportado desde `@horux/shared-ui`**: Reemplazado por `<span>` con clases CSS equivalentes en `seguimiento-auxiliares.tsx`.
- **`Tabs` requería `defaultValue`**: Agregado `defaultValue="carteras"` al componente `<Tabs>` en `carteras/page.tsx`.

### Migración tenant 046 aplicada
- Archivo: `apps/api/src/migrations/tenant/046_asignaciones_obligaciones_tareas.sql`
- Tablas creadas: `obligacion_asignaciones`, `tarea_asignaciones`
- Aplicada a 7 tenants activos.

---

## 2. Fix: Invitación de usuarios no enviaba correo

**Root cause:** `usuarios.service.ts` → `inviteUsuario` generaba `tempPassword` pero nunca llamaba `emailService.sendWelcome()`.

**Fix:**
- Importado `emailService` en `usuarios.service.ts`
- Agregada llamada `emailService.sendWelcome()` cuando se crea un usuario nuevo (`tempPassword !== null`)
- Aplicado también a `createUsuarioGlobal`

### Reenvío de correos a usuarios invitados previos
- Identificados 9 usuarios creados entre jueves 21/05 y hoy sin `lastLogin`
- Generadas nuevas contraseñas temporales, hasheadas en BD, y enviados correos de bienvenida

---

## 3. Fix: Subcartera mostraba contribuyentes de todo el tenant

**Root cause:** `SubcarteraCard` filtraba `available` solo excluyendo los ya asignados a la subcartera, sin verificar que pertenecieran a la cartera padre.

**Fixes:**
- **Frontend:** `SubcarteraCard` ahora recibe `parentEntidadIds` y filtra: `(parentEntidadIds ?? []).includes(c.id)`
- **Backend:** `cartera.service.ts` → `addEntidadToCartera` valida que si es subcartera (`parentId !== null`), la entidad previamente exista en la cartera padre.

---

## 4. Fix: Obligaciones y Tareas no se mostraban (error 500)

**Root cause:** Las queries de `obligaciones.service.ts`, `tareas.service.ts` y `asignaciones.service.ts` hacían `LEFT JOIN users` en la BD de tenant, pero la tabla `users` solo existe en la BD central (`horux360`).

**Error:** `relation "users" does not exist`

**Fixes:**
- Quitados todos los `LEFT JOIN users` de queries de tenant
- En `obligaciones.service.ts` y `tareas.service.ts`: se mantiene solo `auxiliarAsignadoId` (sin nombre)
- En `asignaciones.service.ts`: creada función `resolveUserNames()` que consulta Prisma (BD central) para obtener nombres de usuarios y mapearlos en los resultados
- **Fix adicional:** `asignaciones.controller.ts` usaba `req.params.id` como `obligacionId` cuando en realidad `req.params.id` era `contribuyenteId`. Corregido a `req.params.obligacionId`.

---

## 5. Fix: Endpoint `/carteras/asignaciones` devolvía 500

**Root cause:** Ruta dinámica `GET /:id` estaba definida antes de `GET /asignaciones` en `cartera.routes.ts`. Express interpretaba `"asignaciones"` como parámetro `:id`.

**Error:** `invalid input syntax for type uuid: "asignaciones"`

**Fix:** Reordenadas las rutas estáticas (`/asignaciones`, `/asignaciones/mias`, `/asignaciones/sin-asignar`) antes de las rutas dinámicas (`/:id`).

---

## 6. Fix: Owner no veía asignaciones en "Asignadas"

**Root cause:** `getAsignacionesPorSupervisor` filtraba por `asp.supervisor_user_id = $1`. Un owner no aparece en `auxiliar_supervisores`, por lo que no veía sus propias asignaciones.

**Fix:** La función ahora recibe `role` como parámetro. Si es `owner/cfo/contador`, no filtra por supervisor. Si es `supervisor`, filtra por `auxiliar_supervisores`.

---

## 7. Fix: Lista "Sin asignar" no se refrescaba tras asignar

**Root cause:** Las mutations `useAsignarObligacion`, `useDesasignarObligacion`, `useAsignarTarea`, `useDesasignarTarea` invalidaban `['asignaciones-supervisor']` pero no `['asignaciones-sin-asignar']`.

**Fix:** Agregada invalidación de `['asignaciones-sin-asignar']` a las 4 mutations.

---

## 8. Feature: Seguimiento de Auxiliares — pestaña "Sin asignar"

**Nuevo endpoint:** `GET /carteras/asignaciones/sin-asignar`
- Devuelve obligaciones y tareas activas que NO están en las tablas de asignaciones
- Respeta permisos: owner/cfo ven todo, supervisor solo sus contribuyentes

**Frontend:**
- Reestructurado `SeguimientoAuxiliares` con tabs principales: **"Asignadas"** | **"Sin asignar"**
- Dentro de cada uno, subtabs: **Obligaciones** | **Tareas**
- El modal de asignación funciona en ambas vistas

---

## 9. Feature: Nueva página `/tareas` (Tareas Operativas)

**Nuevo endpoint:** `GET /tareas/mis-tareas`
- Devuelve todas las tareas activas con su periodo actual para los contribuyentes visibles del usuario
- Usa `materializarPeriodos` para cada contribuyente y luego `listTareasConPeriodoPorContribuyentes` para traer todo en batch

**Frontend:**
- Nueva ruta: `/tareas`
- Agregada al sidebar principal en todos los layouts (icono `CheckSquare2`)
- Muestra tareas agrupadas por contribuyente
- Filtros: Todas / Pendientes / Completadas
- Permite marcar/desmarcar tareas como completadas
- Muestra indicadores: atrasada, supervisor-only, recurrencia, fecha límite

---

## 10. Feature: Obligaciones Fiscales ya no se pueden marcar como completadas

En `/pendientes`, se quitó el botón interactivo de check de las obligaciones fiscales. Ahora solo muestra un ícono visual del estado sin acción.

---

## 11. Feature: Invitaciones Trial movido a Admin Usuarios

**Sidebar:** Quitado "Invitaciones Trial" de `adminNavigation` en los 4 layouts (`sidebar.tsx`, `sidebar-compact.tsx`, `sidebar-floating.tsx`, `topnav.tsx`).

**Admin Usuarios:** Agregados tabs con `<Tabs>`:
- **"Usuarios"** — gestión de usuarios global existente
- **"Invitaciones Trial"** — formulario de envío + historial (extraído a componente `admin/_components/invitaciones-trial-tab.tsx`)

---

## Archivos modificados

### Backend
- `apps/api/src/services/usuarios.service.ts`
- `apps/api/src/services/cartera.service.ts`
- `apps/api/src/services/obligaciones.service.ts`
- `apps/api/src/services/tareas.service.ts`
- `apps/api/src/services/asignaciones.service.ts`
- `apps/api/src/controllers/asignaciones.controller.ts`
- `apps/api/src/controllers/tareas.controller.ts`
- `apps/api/src/routes/cartera.routes.ts`
- `apps/api/src/routes/contribuyente.routes.ts`
- `apps/api/src/routes/tareas.routes.ts`

### Frontend
- `apps/web/app/(dashboard)/carteras/page.tsx`
- `apps/web/app/(dashboard)/carteras/seguimiento-auxiliares.tsx`
- `apps/web/app/(dashboard)/pendientes/page.tsx`
- `apps/web/app/(dashboard)/admin/usuarios/page.tsx`
- `apps/web/app/(dashboard)/admin/_components/invitaciones-trial-tab.tsx`
- `apps/web/app/(dashboard)/tareas/page.tsx`
- `apps/web/components/layouts/sidebar.tsx`
- `apps/web/components/layouts/sidebar-compact.tsx`
- `apps/web/components/layouts/sidebar-floating.tsx`
- `apps/web/components/layouts/topnav.tsx`
- `apps/web/lib/api/asignaciones.ts`
- `apps/web/lib/api/tareas-mis.ts`
- `apps/web/lib/hooks/use-asignaciones.ts`
- `apps/web/lib/hooks/use-tareas-mis.ts`

### Migraciones
- `apps/api/src/migrations/tenant/046_asignaciones_obligaciones_tareas.sql`
