< Summary

Information
Class: FAU.Logica.Services.AuditoriaService
Assembly: FAU.Logica
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/AuditoriaService.cs
Line coverage
100%
Covered lines: 35
Uncovered lines: 0
Coverable lines: 35
Total lines: 101
Line coverage: 100%
Branch coverage
81%
Covered branches: 13
Total branches: 16
Branch coverage: 81.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%44100%
GetPagedAsync(...)100%11100%
LogAuditoriaAsync()100%66100%
GetLogContext(...)100%11100%
LogAuditoriaAsync()83.33%66100%
LogAuditoria(...)100%11100%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/AuditoriaService.cs

#LineLine coverage
 1using System.Text.Json;
 2using FAU.DataAccess.Repositories;
 3using FAU.Entidades;
 4using Serilog;
 5
 6namespace FAU.Logica.Services;
 7
 8public class AuditoriaService : IAuditoriaService
 9{
 10    private readonly IAuditoriaRepository _auditoriaRepository;
 11    private readonly IAuditoriaCatalogoResolver _catalogoResolver;
 12
 1313    public AuditoriaService(IAuditoriaRepository auditoriaRepository, IAuditoriaCatalogoResolver catalogoResolver)
 14    {
 1315        _auditoriaRepository = auditoriaRepository ?? throw new ArgumentNullException(nameof(auditoriaRepository));
 1316        _catalogoResolver = catalogoResolver ?? throw new ArgumentNullException(nameof(catalogoResolver));
 1317    }
 18
 19    public Task<(IEnumerable<BitacoraAuditoria> Items, int TotalCount)> GetPagedAsync(
 20        int page,
 21        int pageSize,
 22        string? contexto = null,
 23        string? accion = null,
 24        string? usuario = null,
 25        DateTime? desde = null,
 26        DateTime? hasta = null)
 27    {
 128        return _auditoriaRepository.GetPagedAsync(page, pageSize, contexto, accion, usuario, desde, hasta);
 29    }
 30
 31    /// <summary>
 32    /// Overload recomendado: recibe enums (centralizado) pero resuelve IDs reales por nombre en BD.
 33    /// Esto evita romper auditoría cuando los IDs de catálogo están corridos entre ambientes.
 34    /// </summary>
 35    public async Task LogAuditoriaAsync(
 36        long usuarioId,
 37        AccionEnum accion,
 38        ContextoEnum contexto,
 39        string? host = null,
 40        string? entidad = null,
 41        long? entidadId = null,
 42        object? detalle = null)
 43    {
 1144        var accionId = await _catalogoResolver.GetAccionIdAsync(accion.ToString());
 1145        var contextoId = await _catalogoResolver.GetContextoIdAsync(contexto.ToString());
 46
 1147        await LogAuditoriaAsync(usuarioId, (int)accionId, (int)contextoId, host, entidad, entidadId, detalle);
 48
 49        // Log descriptivo usando nombres de enum en lugar de IDs numéricos
 1150        var logger = Log.Logger.ForContext("Context", GetLogContext(contexto));
 1351        if (entidad != null) logger = logger.ForContext("entidad", entidad);
 1352        if (entidadId.HasValue) logger = logger.ForContext("entidadId", entidadId.Value);
 1353        if (detalle != null) logger = logger.ForContext("detalle", detalle, destructureObjects: true);
 1154        logger.Information("{Accion}", accion.ToString());
 1155    }
 56
 57    private static string GetLogContext(ContextoEnum contexto) =>
 1158        contexto.ToString().ToLowerInvariant();
 59
 60    public async Task LogAuditoriaAsync(
 61        long usuarioId,
 62        int accionId,
 63        int contextoId,
 64        string? host = null,
 65        string? entidad = null,
 66        long? entidadId = null,
 67        object? detalle = null)
 68    {
 1269        var hostFinal = string.IsNullOrWhiteSpace(host) ? "Desconocida" : host;
 70
 1271        string? detalleJson = null;
 1272        if (detalle != null)
 73        {
 274            detalleJson = detalle is string s
 275                ? JsonSerializer.Serialize(s)
 276                : JsonSerializer.Serialize(detalle, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.
 77        }
 78
 79        // 1) Persistir en DB (fuente de verdad)
 1280        await _auditoriaRepository.CreateAsync(new BitacoraAuditoria
 1281        {
 1282            UsuarioId = usuarioId,
 1283            AccionId = accionId,
 1284            ContextoId = contextoId,
 1285            Host = hostFinal,
 1286            Fecha = DateTime.Now,
 1287            Entidad = entidad,
 1288            EntidadId = entidadId,
 1289            Detalle = detalleJson
 1290        });
 91
 92        // El log descriptivo lo emite el overload con enums (que tiene acceso a los nombres).
 93        // Este overload de IDs se usa solo para persistencia.
 1294    }
 95
 96    public void LogAuditoria(long usuarioId, int accionId, int contextoId, string host)
 97    {
 98        // Mantener firma anterior: log + persistencia best-effort.
 199        _ = LogAuditoriaAsync(usuarioId, accionId, contextoId, host);
 1100    }
 101}