Feat: Implementado cálculo de ISR en nóminas

- Agregado campo isr_table_id en tabla months para seleccionar tabla ISR por mes
- Creado servicio IsrCalculator para calcular ISR mensual y quincenal
- Modificado CommissionCalculator para descontar ISR del total a pagar
- Agregado selector de tabla ISR en formulario de crear/editar mes
- Actualizada vista de meses para mostrar tabla ISR asignada
- Actualizados reportes mensual y quincenal para mostrar ISR descontado
This commit is contained in:
2026-04-21 13:45:39 -06:00
parent 4abf89c57f
commit e8aac6eaa5
10 changed files with 213 additions and 21 deletions

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Services;
use App\Models\IsrBracket;
use App\Models\IsrTable;
class IsrCalculator
{
/**
* Calcular ISR mensual dado un ingreso base
* Retorna: ['isr' => float, 'bracket' => array|null, 'effective_rate' => float]
*/
public static function calculateMonthly(float $baseIncome, ?IsrTable $isrTable): array
{
if (!$isrTable || $baseIncome <= 0) {
return [
'isr' => 0,
'bracket' => null,
'effective_rate' => 0,
'taxable_income' => 0,
];
}
$brackets = $isrTable->brackets()->orderBy('lower_limit')->get();
foreach ($brackets as $bracket) {
$upperLimit = $bracket->upper_limit;
// Si es el último bracket (upper_limit es null = "En adelante")
if ($upperLimit === null || $baseIncome <= $upperLimit) {
// Calcular ISR: Cuota Fija + (Excedente × Tasa)
$excedent = $baseIncome - $bracket->lower_limit;
$isr = $bracket->fixed_fee + ($excedent * $bracket->rate / 100);
return [
'isr' => round($isr, 2),
'bracket' => [
'lower_limit' => $bracket->lower_limit,
'upper_limit' => $bracket->upper_limit,
'fixed_fee' => $bracket->fixed_fee,
'rate' => $bracket->rate,
],
'effective_rate' => round(($isr / $baseIncome) * 100, 2),
'taxable_income' => round($baseIncome, 2),
];
}
}
return [
'isr' => 0,
'bracket' => null,
'effective_rate' => 0,
'taxable_income' => 0,
];
}
/**
* Calcular ISR quincenal = ISR mensual / 2
*/
public static function calculateBiweekly(float $monthlyIsr): float
{
return round($monthlyIsr / 2, 2);
}
}