< Summary

Information
Class: FAU.Logica.Services.IrpfCalculator
Assembly: FAU.Logica
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/IrpfCalculator.cs
Line coverage
100%
Covered lines: 78
Uncovered lines: 0
Coverable lines: 78
Total lines: 160
Line coverage: 100%
Branch coverage
100%
Covered branches: 28
Total branches: 28
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
CalcularDeducciones(...)100%1616100%
AplicarFranjas(...)100%1010100%
Calcular(...)100%22100%

File(s)

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

#LineLine coverage
 1namespace FAU.Logica.Services;
 2
 3using FAU.Logica.DTOs;
 4
 5/// <summary>
 6/// Calculadora IRPF sin estado.
 7/// Implementa el calculo de deducciones y la aplicacion de franjas progresivas.
 8/// No accede a la base de datos: recibe todos los datos por parametro.
 9/// </summary>
 10public class IrpfCalculator
 11{
 12    /// <summary>
 13    /// Calcula deducciones IRPF: aportes jubilatorios, dependientes y profesional.
 14    /// La deduccion profesional llega ya valorizada desde el Form 3100 vigente.
 15    /// </summary>
 16    public DetalleDeduccionesResultado CalcularDeducciones(
 17        decimal ingresoGravado,
 18        decimal montepio,
 19        decimal fonasa,
 20        decimal frl,
 21        List<DeduccionDto> deducciones,
 22        ParametrosIrpfDto parametros)
 23    {
 1424        var resultado = new DetalleDeduccionesResultado();
 25
 26        // 1. Deduccion por aportes jubilatorios (montepio + FONASA/Sanidad). FRL no integra IRPF_DED.PRG.
 1427        resultado.Aportes = montepio + fonasa;
 28
 29        // 2. Deducciones por dependientes y profesional.
 4430        foreach (var deduccion in deducciones)
 31        {
 832            if (deduccion.Tipo == "hijo_menor")
 33            {
 334                var monto = parametros.BpcMensual * 20 / 12;
 335                resultado.Hijos += deduccion.Monto > 0m
 336                    ? deduccion.Monto
 337                    : deduccion.Cantidad * monto;
 38            }
 539            else if (deduccion.Tipo == "hijo_discapacidad")
 40            {
 241                var monto = parametros.BpcMensual * 40 / 12;
 242                resultado.Hijos += deduccion.Monto > 0m
 243                    ? deduccion.Monto
 244                    : deduccion.Cantidad * monto;
 45            }
 346            else if (deduccion.Tipo == "conyuge_sin_ingresos")
 47            {
 248                if (deduccion.Cantidad > 0)
 249                    resultado.Conyuge = parametros.BpcMensual * 20 / 12;
 50            }
 151            else if (deduccion.Tipo == "profesional")
 52            {
 153                resultado.Profesional += Math.Max(0m, deduccion.Monto);
 54            }
 55        }
 56
 1457        return resultado;
 58    }
 59
 60    /// <summary>
 61    /// Aplica las franjas progresivas IRPF a la base dada.
 62    /// Retorna el total y el detalle por franja.
 63    /// </summary>
 64    public (decimal TotalIrpf, List<DetalleFranjaResultado> Detalles) AplicarFranjas(
 65        decimal baseParaFranjas,
 66        List<FranjaIrpfCalculoDto> franjas,
 67        decimal bpcMensual)
 68    {
 1169        var totalIrpf = decimal.Zero;
 1170        var detalles = new List<DetalleFranjaResultado>();
 71
 1272        if (baseParaFranjas < 0) baseParaFranjas = 0;
 73
 1174        var restante = baseParaFranjas;
 75
 12476        foreach (var franja in franjas.OrderBy(f => f.NumeroFranja))
 77        {
 3578            if (restante <= 0) break;
 79
 2380            var limiteInf = franja.DesdeBpc * bpcMensual;
 2381            var limiteSup = franja.HastaBpc.HasValue
 2382                ? franja.HastaBpc.Value * bpcMensual
 2383                : decimal.MaxValue;
 84
 2385            var ancho = limiteSup - limiteInf;
 2386            var montoEnFranja = Math.Min(restante, ancho);
 2387            var impuestoFranja = montoEnFranja * franja.Tasa;
 88
 2389            if (montoEnFranja > 0)
 90            {
 2391                detalles.Add(new DetalleFranjaResultado
 2392                {
 2393                    FranjaId = franja.FranjaId,
 2394                    NumeroFranja = franja.NumeroFranja,
 2395                    BaseFranja = montoEnFranja,
 2396                    Tasa = franja.Tasa,
 2397                    Impuesto = impuestoFranja
 2398                });
 99
 23100                totalIrpf += impuestoFranja;
 101            }
 102
 23103            restante -= ancho;
 104        }
 105
 11106        return (totalIrpf, detalles);
 107    }
 108
 109    /// <summary>
 110    /// Calcula IRPF con el enfoque de credito fiscal usado por el legacy:
 111    /// aplica franjas sobre el ingreso bruto, calcula el credito sobre deducciones
 112    /// y resta ese credito al impuesto bruto.
 113    /// </summary>
 114    public ResultadoIrpf Calcular(CalcularIrpfRequest request)
 115    {
 7116        var bpcMensual = request.Parametros.BpcMensual;
 117
 118        // Cuando viene Adicional6 > 0, la base para franjas es baseSdlAportes * 1.06,
 119        // pasada como IngresoGravados + Adicional6 desde el pipeline.
 7120        var baseParaFranjas = request.IngresoGravados + request.Adicional6;
 121
 7122        var (irpfBruto, detalleFranjas) = AplicarFranjas(
 7123            baseParaFranjas,
 7124            request.Franjas,
 7125            bpcMensual);
 126
 7127        var deducciones = CalcularDeducciones(
 7128            request.IngresoGravados,
 7129            request.Montepio,
 7130            request.Fonasa,
 7131            request.Frl,
 7132            request.Deducciones,
 7133            request.Parametros);
 134
 7135        var totalDeducciones =
 7136            deducciones.Aportes +
 7137            deducciones.Hijos +
 7138            deducciones.Conyuge +
 7139            deducciones.Profesional;
 140
 7141        var umbral15Bpc = request.Parametros.UmbralDeduccionBpc * bpcMensual;
 7142        var tasaCredito = request.IngresoGravados >= umbral15Bpc
 7143            ? request.Parametros.TasaDeduccionAlta
 7144            : request.Parametros.TasaDeduccionBaja;
 145
 7146        var credito = totalDeducciones * tasaCredito;
 7147        var totalIrpf = Math.Max(0m, irpfBruto - credito);
 148
 7149        return new ResultadoIrpf
 7150        {
 7151            IngresoGravado = request.IngresoGravados,
 7152            Deducciones = deducciones,
 7153            TasaCredito = tasaCredito,
 7154            TotalDeducciones = totalDeducciones,
 7155            IrpfBruto = irpfBruto,
 7156            TotalIrpf = totalIrpf,
 7157            DetallePorFranja = detalleFranjas
 7158        };
 159    }
 160}