< 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
100%
Covered lines: 85
Uncovered lines: 0
Coverable lines: 85
Total lines: 148
Line coverage: 100%
Branch coverage
93%
Covered branches: 30
Total branches: 32
Branch coverage: 93.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%11100%
AgregarPersonaACargoAsync()100%44100%
EliminarPersonaACargoAsync()100%44100%
SubirArchivoAsync()87.5%88100%
ObtenerArchivoAsync()100%66100%
SanitizarNombre(...)50%22100%

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
 2014    public Form3100Service(
 2015        IForm3100Repository repo,
 2016        IPersonalRepository personalRepo,
 2017        IDocumentoRepository docRepo,
 2018        IStorageService storage,
 2019        IPeriodoGuard periodoGuard)
 20    {
 2021        _repo         = repo;
 2022        _personalRepo = personalRepo;
 2023        _docRepo      = docRepo;
 2024        _storage      = storage;
 2025        _periodoGuard = periodoGuard;
 2026    }
 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
 161    public Task<Form3100?> GetByIdAsync(long id) => _repo.GetByIdAsync(id);
 62
 63    public async Task<Form3100PersonaACargo> AgregarPersonaACargoAsync(long form3100Id, Form3100PersonaACargo persona)
 64    {
 365        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 366        var form = await _repo.GetByIdAsync(form3100Id)
 367            ?? 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    {
 378        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 379        var p = await _repo.GetPersonaACargoAsync(personaCargoId)
 380            ?? 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    {
 390        await _periodoGuard.VerificarPeriodoAbiertoAsync();
 391        var form = await _repo.GetByIdAsync(form3100Id)
 392            ?? throw new ArgumentException($"Form3100 {form3100Id} no encontrado.");
 93
 294        var nombreSanitizado = SanitizarNombre(nombreOriginal);
 295        var rutaRelativa     = $"form3100/{form3100Id}/{nombreSanitizado}";
 96
 97        // Eliminar archivo anterior si existe
 298        if (form.DocumentoId.HasValue)
 99        {
 1100            var docAnterior = await _docRepo.GetByIdAsync(form.DocumentoId.Value);
 1101            if (docAnterior != null)
 102            {
 1103                await _storage.EliminarAsync(docAnterior.RutaRelativa);
 1104                await _docRepo.DeleteAsync(docAnterior.Id);
 105            }
 1106        }
 107
 108        // Obtener tamaño
 2109        var tamanio = contenido.CanSeek ? contenido.Length : 0;
 110
 2111        await _storage.GuardarAsync(contenido, rutaRelativa, contentType);
 112
 2113        var documento = await _docRepo.CreateAsync(new Documento
 2114        {
 2115            Tipo            = "form3100",
 2116            EntidadId       = form3100Id,
 2117            RutaRelativa    = rutaRelativa,
 2118            NombreOriginal  = nombreOriginal,
 2119            ContentType     = contentType,
 2120            TamanioBytes    = tamanio,
 2121            UsuarioCargaId  = usuarioId
 2122        });
 123
 2124        form.DocumentoId = documento.Id;
 2125        await _repo.UpdateAsync(form);
 126
 2127        return rutaRelativa;
 2128    }
 129
 130    public async Task<(Stream Contenido, string NombreOriginal, string ContentType)> ObtenerArchivoAsync(long form3100Id
 131    {
 3132        var form = await _repo.GetByIdAsync(form3100Id)
 3133            ?? throw new ArgumentException($"Form3100 {form3100Id} no encontrado.");
 134
 2135        if (!form.DocumentoId.HasValue || form.Documento == null)
 1136            throw new KeyNotFoundException($"Form3100 {form3100Id} no tiene archivo adjunto.");
 137
 1138        var stream = await _storage.ObtenerAsync(form.Documento.RutaRelativa);
 1139        return (stream, form.Documento.NombreOriginal, form.Documento.ContentType);
 1140    }
 141
 142    private static string SanitizarNombre(string nombre)
 143    {
 2144        var invalidos = Path.GetInvalidFileNameChars();
 22145        var limpio    = string.Concat(nombre.Select(c => invalidos.Contains(c) ? '_' : c));
 2146        return limpio.Replace(' ', '_').ToLower();
 147    }
 148}