- Nueva tabla isr_tables y isr_brackets en BD - Controlador IsrController para CRUD de tablas ISR - Integración con pestaña ISR en settings - Soporte para importación via CSV - Captura manual de brackets
228 lines
6.8 KiB
PHP
228 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\IsrBracket;
|
|
use App\Models\IsrTable;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
|
class IsrController extends Controller
|
|
{
|
|
/**
|
|
* Lista todas las tablas ISR
|
|
*/
|
|
public function index()
|
|
{
|
|
$isrTables = IsrTable::with('brackets')->orderBy('year', 'desc')->get();
|
|
return view('settings.isr.index', compact('isrTables'));
|
|
}
|
|
|
|
/**
|
|
* Crea nueva tabla por año
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'year' => 'required|integer|min:2000|max:2100|unique:isr_tables,year',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return redirect()->route('settings.index', ['tab' => 'isr'])
|
|
->withErrors($validator)
|
|
->withInput();
|
|
}
|
|
|
|
$isrTable = IsrTable::create([
|
|
'year' => $request->input('year'),
|
|
]);
|
|
|
|
return redirect()->route('settings.index', ['tab' => 'isr'])
|
|
->with('success', 'Tabla ISR para ' . $isrTable->year . ' creada. Ahora agrega los brackets.');
|
|
}
|
|
|
|
/**
|
|
* Formulario edición de brackets
|
|
*/
|
|
public function edit(IsrTable $isrTable)
|
|
{
|
|
$isrTable->load('brackets');
|
|
return view('settings.isr.edit', compact('isrTable'));
|
|
}
|
|
|
|
/**
|
|
* Guarda brackets manuales
|
|
*/
|
|
public function updateBrackets(Request $request, IsrTable $isrTable)
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'brackets' => 'required|array|min:1',
|
|
'brackets.*.lower_limit' => 'required|numeric|min:0',
|
|
'brackets.*.upper_limit' => 'nullable|numeric|min:0',
|
|
'brackets.*.fixed_fee' => 'required|numeric|min:0',
|
|
'brackets.*.rate' => 'required|numeric|min:0|max:100',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return redirect()->route('settings.isr.edit', $isrTable)
|
|
->withErrors($validator)
|
|
->withInput();
|
|
}
|
|
|
|
// Eliminar brackets existentes
|
|
$isrTable->brackets()->delete();
|
|
|
|
// Crear nuevos brackets
|
|
$bracketsData = $request->input('brackets');
|
|
$order = 0;
|
|
|
|
// Ordenar brackets por lower_limit antes de guardar
|
|
usort($bracketsData, function ($a, $b) {
|
|
return floatval($a['lower_limit']) - floatval($b['lower_limit']);
|
|
});
|
|
|
|
foreach ($bracketsData as $bracketData) {
|
|
$isrTable->brackets()->create([
|
|
'lower_limit' => floatval($bracketData['lower_limit']),
|
|
'upper_limit' => isset($bracketData['upper_limit']) && $bracketData['upper_limit'] !== ''
|
|
? floatval($bracketData['upper_limit'])
|
|
: null,
|
|
'fixed_fee' => floatval($bracketData['fixed_fee']),
|
|
'rate' => floatval($bracketData['rate']),
|
|
'order' => $order++,
|
|
]);
|
|
}
|
|
|
|
return redirect()->route('settings.index', ['tab' => 'isr'])
|
|
->with('success', 'Brackets actualizados correctamente.');
|
|
}
|
|
|
|
/**
|
|
* Importa CSV
|
|
*/
|
|
public function uploadCsv(Request $request, IsrTable $isrTable)
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'csv_file' => 'required|file|mimes:csv,txt',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return redirect()->route('settings.isr.edit', $isrTable)
|
|
->withErrors($validator)
|
|
->withInput();
|
|
}
|
|
|
|
$file = $request->file('csv_file');
|
|
$content = file_get_contents($file->getRealPath());
|
|
$lines = explode("\n", $content);
|
|
|
|
$brackets = [];
|
|
$firstLine = true;
|
|
|
|
foreach ($lines as $line) {
|
|
$line = trim($line);
|
|
|
|
// Ignorar primera línea (encabezados vacíos)
|
|
if ($firstLine) {
|
|
$firstLine = false;
|
|
continue;
|
|
}
|
|
|
|
if (empty($line)) {
|
|
continue;
|
|
}
|
|
|
|
// Parsear línea CSV
|
|
$values = str_getcsv($line);
|
|
|
|
if (count($values) < 4) {
|
|
continue;
|
|
}
|
|
|
|
$lowerLimit = $this->parseCsvValue($values[0]);
|
|
$upperLimit = $this->parseCsvValue($values[1]);
|
|
$fixedFee = $this->parseCsvValue($values[2]);
|
|
$rate = $this->parseCsvValue($values[3]);
|
|
|
|
// Ignorar si no hay lower_limit válido
|
|
if ($lowerLimit === null || $lowerLimit < 0) {
|
|
continue;
|
|
}
|
|
|
|
// Default null values to 0
|
|
$fixedFee = $fixedFee ?? 0;
|
|
$rate = $rate ?? 0;
|
|
|
|
$brackets[] = [
|
|
'lower_limit' => $lowerLimit,
|
|
'upper_limit' => $upperLimit,
|
|
'fixed_fee' => $fixedFee,
|
|
'rate' => $rate,
|
|
];
|
|
}
|
|
|
|
// Ordenar brackets por lower_limit
|
|
usort($brackets, function ($a, $b) {
|
|
return $a['lower_limit'] - $b['lower_limit'];
|
|
});
|
|
|
|
if (empty($brackets)) {
|
|
return redirect()->route('settings.index', ['tab' => 'isr'])
|
|
->with('error', 'No se encontraron brackets válidos en el archivo CSV.');
|
|
}
|
|
|
|
// Eliminar brackets existentes
|
|
$isrTable->brackets()->delete();
|
|
|
|
// Crear nuevos brackets
|
|
$order = 0;
|
|
foreach ($brackets as $bracket) {
|
|
$isrTable->brackets()->create([
|
|
'lower_limit' => $bracket['lower_limit'],
|
|
'upper_limit' => $bracket['upper_limit'],
|
|
'fixed_fee' => $bracket['fixed_fee'],
|
|
'rate' => $bracket['rate'],
|
|
'order' => $order++,
|
|
]);
|
|
}
|
|
|
|
return redirect()->route('settings.index', ['tab' => 'isr'])
|
|
->with('success', 'Brackets importados correctamente desde el CSV.');
|
|
}
|
|
|
|
/**
|
|
* Elimina tabla ISR
|
|
*/
|
|
public function destroy(IsrTable $isrTable)
|
|
{
|
|
$year = $isrTable->year;
|
|
$isrTable->delete();
|
|
|
|
return redirect()->route('settings.index', ['tab' => 'isr'])
|
|
->with('success', 'Tabla ISR para ' . $year . ' eliminada.');
|
|
}
|
|
|
|
/**
|
|
* Convierte valor CSV como "3,537.15" a 3537.15
|
|
*/
|
|
private function parseCsvValue(string $val): ?float
|
|
{
|
|
// Limpiar comillas y espacios
|
|
$val = trim($val, '"\' ');
|
|
|
|
// Manejar "En adelante" como null
|
|
if (in_array(strtolower($val), ['en adelante', 'en adelante ', 'null', ''])) {
|
|
return null;
|
|
}
|
|
|
|
// Eliminar comas de miles
|
|
$val = str_replace(',', '', $val);
|
|
|
|
// Convertir a número
|
|
$num = floatval($val);
|
|
|
|
// Permitir 0 como valor válido, pero null para valores negativos o no numéricos
|
|
return is_numeric($val) ? $num : null;
|
|
}
|
|
} |