< Summary

Information
Class: FAU.Logica.Services.Form3100Service
Assembly: FAU.Logica
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/Form3100Service.cs
Line coverage
55%
Covered lines: 47
Uncovered lines: 38
Coverable lines: 85
Total lines: 148
Line coverage: 55.2%
Branch coverage
43%
Covered branches: 14
Total branches: 32
Branch coverage: 43.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
CrearAsync()100%44100%
GetHistorialAsync()100%22100%
GetVigenteParaPeriodoAsync()100%22100%
GetByIdAsync(...)100%210%
AgregarPersonaACargoAsync()75%44100%
EliminarPersonaACargoAsync()75%44100%
SubirArchivoAsync()0%7280%
ObtenerArchivoAsync()0%4260%
SanitizarNombre(...)0%620%

File(s)

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

#LineLine coverage
 1using FAU.DataAccess.Repositories;
 2using FAU.Entidades;
 3
 4namespace FAU.Logica.Services;
 5
 6public class Form3100Service : IForm3100Service
 7{
 8    private readonly IForm3100Repository _repo;
 9    private readonly IPersonalRepository _personalRepo;
 10    private readonly IDocumentoRepository _docRepo;
 11    private readonly IStorageService _storage;
 12    private readonly IPeriodoGuard _periodoGuard;
 13
 1114    public Form3100Service(
 1115        IForm3100Repository repo,
 1116        IPersonalRepository personalRepo,
 1117        IDocumentoRepository docRepo,
 1118        IStorageService storage,
 1119        IPeriodoGuard periodoGuard)
 20    {
 1121        _repo         = repo;
 1122        _personalRepo = personalRepo;
 1123        _docRepo      = docRepo;
 1124        _storage      = storage;
 1125        _periodoGuard = periodoGuard;
 1126    }
 27
 28    public async Task<Form3100> CrearAsync(string cedulaTitular, Form3100 form, long usuarioId)
 29    {
 330        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 331        var relacion = await _personalRepo.GetByCedulaAsync(cedulaTitular)
 332            ?? throw new ArgumentException($"Funcionario con cédula {cedulaTitular} no encontrado.");
 33
 234        var personaId = relacion.PersonaId;
 35
 236        if (await _repo.ExisteVigenciaAsync(personaId, form.VigenteDesde_Anio, form.VigenteDesde_Mes))
 137            throw new InvalidOperationException(
 138                $"Ya existe un formulario para {cedulaTitular} con vigencia {form.VigenteDesde_Mes:D2}/{form.VigenteDesd
 39
 140        form.PersonaId          = personaId;
 141        form.UsuarioCreacionId  = usuarioId;
 142        form.FechaCreacion      = DateTime.Now;
 43
 144        return await _repo.CreateAsync(form);
 145    }
 46
 47    public async Task<IEnumerable<Form3100>> GetHistorialAsync(string cedulaTitular, int? anio = null, int? mes = null)
 48    {
 249        var relacion = await _personalRepo.GetByCedulaAsync(cedulaTitular);
 350        if (relacion == null) return Enumerable.Empty<Form3100>();
 151        return await _repo.GetHistorialAsync(relacion.PersonaId, anio, mes);
 252    }
 53
 54    public async Task<Form3100?> GetVigenteParaPeriodoAsync(string cedulaTitular, int anio, int mes)
 55    {
 256        var relacion = await _personalRepo.GetByCedulaAsync(cedulaTitular);
 357        if (relacion == null) return null;
 158        return await _repo.GetVigenteParaPeriodoAsync(relacion.PersonaId, anio, mes);
 259    }
 60
 061    public Task<Form3100?> GetByIdAsync(long id) => _repo.GetByIdAsync(id);
 62
 63    public async Task<Form3100PersonaACargo> AgregarPersonaACargoAsync(long form3100Id, Form3100PersonaACargo persona)
 64    {
 265        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 266        var form = await _repo.GetByIdAsync(form3100Id)
 267            ?? throw new ArgumentException($"Form3100 {form3100Id} no encontrado.");
 68
 269        if (!new[] { 0, 50, 100 }.Contains((int)persona.PorcentajeAtribucion))
 170            throw new ArgumentException("PorcentajeAtribucion debe ser 0, 50 o 100.");
 71
 172        persona.Form3100Id = form3100Id;
 173        return await _repo.AddPersonaACargoAsync(persona);
 174    }
 75
 76    public async Task EliminarPersonaACargoAsync(long form3100Id, long personaCargoId)
 77    {
 278        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 279        var p = await _repo.GetPersonaACargoAsync(personaCargoId)
 280            ?? throw new ArgumentException($"Persona a cargo {personaCargoId} no encontrada.");
 81
 282        if (p.Form3100Id != form3100Id)
 183            throw new ArgumentException("La persona a cargo no pertenece al formulario indicado.");
 84
 185        await _repo.DeletePersonaACargoAsync(personaCargoId);
 186    }
 87
 88    public async Task<string> SubirArchivoAsync(long form3100Id, Stream contenido, string nombreOriginal, string content
 89    {
 090        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 091        var form = await _repo.GetByIdAsync(form3100Id)
 092            ?? throw new ArgumentException($"Form3100 {form3100Id} no encontrado.");
 93
 094        var nombreSanitizado = SanitizarNombre(nombreOriginal);
 095        var rutaRelativa     = $"form3100/{form3100Id}/{nombreSanitizado}";
 96
 97        // Eliminar archivo anterior si existe
 098        if (form.DocumentoId.HasValue)
 99        {
 0100            var docAnterior = await _docRepo.GetByIdAsync(form.DocumentoId.Value);
 0101            if (docAnterior != null)
 102            {
 0103                await _storage.EliminarAsync(docAnterior.RutaRelativa);
 0104                await _docRepo.DeleteAsync(docAnterior.Id);
 105            }
 0106        }
 107
 108        // Obtener tamaño
 0109        var tamanio = contenido.CanSeek ? contenido.Length : 0;
 110
 0111        await _storage.GuardarAsync(contenido, rutaRelativa, contentType);
 112
 0113        var documento = await _docRepo.CreateAsync(new Documento
 0114        {
 0115            Tipo            = "form3100",
 0116            EntidadId       = form3100Id,
 0117            RutaRelativa    = rutaRelativa,
 0118            NombreOriginal  = nombreOriginal,
 0119            ContentType     = contentType,
 0120            TamanioBytes    = tamanio,
 0121            UsuarioCargaId  = usuarioId
 0122        });
 123
 0124        form.DocumentoId = documento.Id;
 0125        await _repo.UpdateAsync(form);
 126
 0127        return rutaRelativa;
 0128    }
 129
 130    public async Task<(Stream Contenido, string NombreOriginal, string ContentType)> ObtenerArchivoAsync(long form3100Id
 131    {
 0132        var form = await _repo.GetByIdAsync(form3100Id)
 0133            ?? throw new ArgumentException($"Form3100 {form3100Id} no encontrado.");
 134
 0135        if (!form.DocumentoId.HasValue || form.Documento == null)
 0136            throw new KeyNotFoundException($"Form3100 {form3100Id} no tiene archivo adjunto.");
 137
 0138        var stream = await _storage.ObtenerAsync(form.Documento.RutaRelativa);
 0139        return (stream, form.Documento.NombreOriginal, form.Documento.ContentType);
 0140    }
 141
 142    private static string SanitizarNombre(string nombre)
 143    {
 0144        var invalidos = Path.GetInvalidFileNameChars();
 0145        var limpio    = string.Concat(nombre.Select(c => invalidos.Contains(c) ? '_' : c));
 0146        return limpio.Replace(' ', '_').ToLower();
 147    }
 148}