# 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 `` con clases CSS equivalentes en `seguimiento-auxiliares.tsx`. - **`Tabs` requería `defaultValue`**: Agregado `defaultValue="carteras"` al componente `` 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 ``: - **"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`