diff --git a/src/modules/admin/admin-access.controller.ts b/src/modules/admin/admin-access.controller.ts index 2fa64e3..852bea1 100644 --- a/src/modules/admin/admin-access.controller.ts +++ b/src/modules/admin/admin-access.controller.ts @@ -41,7 +41,17 @@ export class AdminAccessController { @Put('users/:id') updateUserAccess( @Param('id') id: string, - @Body() body: { perfilId?: number | null; areaId?: number | null }, + @Body() body: { + perfilId?: number | null; + perfilIds?: number[]; + areaId?: number | null; + especialidades?: Array<{ + areaId: number; + funcao?: string | null; + principal?: boolean; + ativo?: boolean; + }>; + }, ) { return this.adminAccessService.updateUserAccess(Number(id), body); } diff --git a/src/modules/admin/admin-access.service.ts b/src/modules/admin/admin-access.service.ts index 3b9b7f2..aa3834b 100644 --- a/src/modules/admin/admin-access.service.ts +++ b/src/modules/admin/admin-access.service.ts @@ -3,7 +3,14 @@ import { DatabaseService } from '../../infra/database/database.service'; interface AccessUpdateInput { perfilId?: number | null; + perfilIds?: number[]; areaId?: number | null; + especialidades?: Array<{ + areaId: number; + funcao?: string | null; + principal?: boolean; + ativo?: boolean; + }>; } interface AreaInput { @@ -130,10 +137,17 @@ export class AdminAccessService { a.ativo, a.responsavel_usuario_id, r.nome AS responsavel_nome, + COALESCE( + JSON_AGG(DISTINCT JSONB_BUILD_OBJECT('id', su.id, 'nome', su.nome)) + FILTER (WHERE su.id IS NOT NULL), + '[]' + ) AS supervisores, COUNT(DISTINCT ua.usuario_id)::INTEGER AS members FROM areas a LEFT JOIN usuarios r ON r.id = a.responsavel_usuario_id LEFT JOIN usuarios_areas ua ON ua.area_id = a.id AND ua.ativo = TRUE + LEFT JOIN usuarios_areas sua ON sua.area_id = a.id AND sua.ativo = TRUE AND sua.funcao = 'Supervisor' + LEFT JOIN usuarios su ON su.id = sua.usuario_id GROUP BY a.id, r.nome ORDER BY a.nome `, @@ -156,7 +170,7 @@ export class AdminAccessService { '[]' ) AS perfis, COALESCE( - JSON_AGG(DISTINCT JSONB_BUILD_OBJECT('id', a.id, 'nome', a.nome, 'principal', ua.principal)) + JSON_AGG(DISTINCT JSONB_BUILD_OBJECT('id', a.id, 'nome', a.nome, 'principal', ua.principal, 'funcao', ua.funcao)) FILTER (WHERE a.id IS NOT NULL AND ua.ativo = TRUE), '[]' ) AS areas @@ -174,6 +188,7 @@ export class AdminAccessService { const perfis = Array.isArray(user.perfis) ? user.perfis : []; const areas = Array.isArray(user.areas) ? user.areas : []; const primaryArea = areas.find((area) => area.principal) || areas[0] || null; + const isAdmin = perfis.some((perfil) => perfil.nome === 'Admin'); return { id: user.id, @@ -184,7 +199,7 @@ export class AdminAccessService { areas, perfilPrincipal: perfis[0] || null, areaPrincipal: primaryArea, - accessStatus: perfis.length && areas.length ? 'assigned' : 'unassigned', + accessStatus: perfis.length && (areas.length || isAdmin) ? 'assigned' : 'unassigned', }; }); } @@ -194,22 +209,41 @@ export class AdminAccessService { await client.query('DELETE FROM usuarios_perfis WHERE usuario_id = $1', [usuarioId]); await client.query('DELETE FROM usuarios_areas WHERE usuario_id = $1', [usuarioId]); - if (input.perfilId) { + const perfilIds = Array.isArray(input.perfilIds) + ? input.perfilIds + : input.perfilId + ? [input.perfilId] + : []; + + for (const perfilId of [...new Set(perfilIds.filter(Boolean))]) { await client.query( 'INSERT INTO usuarios_perfis (usuario_id, perfil_id) VALUES ($1, $2) ON CONFLICT DO NOTHING', - [usuarioId, input.perfilId], + [usuarioId, perfilId], ); } - if (input.areaId) { + const especialidades = Array.isArray(input.especialidades) + ? input.especialidades + : input.areaId + ? [{ areaId: input.areaId, funcao: 'Agente', principal: true, ativo: true }] + : []; + let hasPrincipal = false; + + for (const item of especialidades) { + const areaId = Number(item.areaId); + if (!areaId) continue; + + const isPrincipal = Boolean(item.principal) && !hasPrincipal; + hasPrincipal = hasPrincipal || isPrincipal; + await client.query( ` - INSERT INTO usuarios_areas (usuario_id, area_id, principal, ativo) - VALUES ($1, $2, TRUE, TRUE) + INSERT INTO usuarios_areas (usuario_id, area_id, funcao, principal, ativo) + VALUES ($1, $2, $3, $4, $5) ON CONFLICT (usuario_id, area_id) - DO UPDATE SET principal = TRUE, ativo = TRUE, updated_at = NOW() + DO UPDATE SET funcao = EXCLUDED.funcao, principal = EXCLUDED.principal, ativo = EXCLUDED.ativo, updated_at = NOW() `, - [usuarioId, input.areaId], + [usuarioId, areaId, this.normalizeRole(item.funcao), isPrincipal, item.ativo !== false], ); } }); @@ -298,4 +332,9 @@ export class AdminAccessService { const text = String(value || '').trim(); return text || null; } + + private normalizeRole(value?: string | null) { + const role = String(value || '').trim(); + return role === 'Supervisor' ? 'Supervisor' : 'Agente'; + } }