Ahora si(?

This commit is contained in:
Laucha1312
2026-06-04 15:01:53 -03:00
parent 47408d49fc
commit 8fc619f9e7
127 changed files with 12952 additions and 0 deletions
@@ -0,0 +1,115 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\AdminUser;
use App\Models\Club;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
class AdminUserController extends Controller
{
private function checkSuperAdmin(Request $request)
{
if (!session('admin_logged_in') || session('admin_role') != 1) {
abort(403, 'Acceso denegado. Solo Súper Administradores.');
}
}
public function index(Request $request)
{
$this->checkSuperAdmin($request);
$usuarios = AdminUser::with('club')->orderBy('id', 'desc')->paginate(20);
return view('admin.usuarios.index', compact('usuarios'));
}
public function create(Request $request)
{
$this->checkSuperAdmin($request);
$usuario = null;
$clubes = Club::orderBy('nombre')->get();
return view('admin.usuarios.form', compact('usuario', 'clubes'));
}
public function store(Request $request)
{
$this->checkSuperAdmin($request);
$data = $request->validate([
'username' => 'required|string|max:50|unique:admin_users',
'password' => 'required|string|min:6',
'role' => 'required|integer|in:1,2',
'id_club' => 'nullable|integer|exists:clubes,id_club'
]);
if ($data['role'] == 2 && empty($data['id_club'])) {
return back()->withErrors(['id_club' => 'Si el rol es Admin de Club, se requiere un club asociado.'])->withInput();
}
if ($data['role'] == 1) {
$data['id_club'] = null; // Superadmins no pertenecen a un club específico en este contexto
}
$data['password'] = Hash::make($data['password']);
AdminUser::create($data);
return redirect()->route('admin.usuarios.index')->with('admin_msg', 'Administrador creado exitosamente.');
}
public function edit(Request $request, $id)
{
$this->checkSuperAdmin($request);
$usuario = AdminUser::findOrFail($id);
$clubes = Club::orderBy('nombre')->get();
return view('admin.usuarios.form', compact('usuario', 'clubes'));
}
public function update(Request $request, $id)
{
$this->checkSuperAdmin($request);
$usuario = AdminUser::findOrFail($id);
$data = $request->validate([
'username' => ['required', 'string', 'max:50', Rule::unique('admin_users')->ignore($usuario->id)],
'password' => 'nullable|string|min:6',
'role' => 'required|integer|in:1,2',
'id_club' => 'nullable|integer|exists:clubes,id_club'
]);
if ($data['role'] == 2 && empty($data['id_club'])) {
return back()->withErrors(['id_club' => 'Si el rol es Admin de Club, se requiere un club asociado.'])->withInput();
}
if ($data['role'] == 1) {
$data['id_club'] = null;
}
if (!empty($data['password'])) {
$data['password'] = Hash::make($data['password']);
} else {
unset($data['password']);
}
$usuario->update($data);
return redirect()->route('admin.usuarios.index')->with('admin_msg', 'Administrador actualizado exitosamente.');
}
public function destroy(Request $request, $id)
{
$this->checkSuperAdmin($request);
$usuario = AdminUser::findOrFail($id);
if ($usuario->id == session('admin_id')) {
return back()->with('admin_error', 'No puedes eliminar tu propio usuario.');
}
$usuario->delete();
return redirect()->route('admin.usuarios.index')->with('admin_msg', 'Administrador eliminado.');
}
}
@@ -0,0 +1,113 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\CarouselItem;
use App\Services\ImageOptimizer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
class CarouselItemController extends Controller
{
private function checkGeneralAdmin(Request $request): void
{
if (!session('admin_logged_in') || !in_array(session('admin_role'), [1, 2])) {
abort(403, 'Acceso denegado');
}
}
public function index(Request $request)
{
$this->checkGeneralAdmin($request);
$items = CarouselItem::orderBy('orden', 'asc')->latest()->get();
return view('admin.carousel.index', compact('items'));
}
public function create(Request $request)
{
$this->checkGeneralAdmin($request);
return view('admin.carousel.create');
}
public function store(Request $request)
{
$this->checkGeneralAdmin($request);
$request->validate([
'titulo' => 'nullable|string|max:255',
'subtitulo' => 'nullable|string|max:255',
'boton_texto' => 'nullable|string|max:255',
'boton_enlace' => 'nullable|string|max:255',
'imagen' => 'required|image|mimes:jpeg,png,jpg,webp|max:5120',
'orden' => 'nullable|integer',
'activo' => 'nullable|boolean',
]);
$data = $request->except('imagen');
$data['activo'] = $request->has('activo');
if ($request->hasFile('imagen')) {
$path = app(ImageOptimizer::class)->storeAndOptimize($request->file('imagen'), 'carousel');
$data['imagen'] = 'storage/' . $path;
}
CarouselItem::create($data);
return redirect()->route('admin.carousel.index')->with('admin_msg', 'Slide creado exitosamente.');
}
public function edit(Request $request, CarouselItem $carouselItem)
{
$this->checkGeneralAdmin($request);
return view('admin.carousel.edit', compact('carouselItem'));
}
public function update(Request $request, CarouselItem $carouselItem)
{
$this->checkGeneralAdmin($request);
$request->validate([
'titulo' => 'nullable|string|max:255',
'subtitulo' => 'nullable|string|max:255',
'boton_texto' => 'nullable|string|max:255',
'boton_enlace' => 'nullable|string|max:255',
'imagen' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:5120',
'orden' => 'nullable|integer',
'activo' => 'nullable|boolean',
]);
$data = $request->except('imagen');
$data['activo'] = $request->has('activo');
if ($request->hasFile('imagen')) {
// Eliminar imagen anterior si existe
if ($carouselItem->imagen) {
$oldPath = public_path($carouselItem->imagen);
if (File::exists($oldPath)) {
File::delete($oldPath);
}
}
$path = app(ImageOptimizer::class)->storeAndOptimize($request->file('imagen'), 'carousel');
$data['imagen'] = 'storage/' . $path;
}
$carouselItem->update($data);
return redirect()->route('admin.carousel.index')->with('admin_msg', 'Slide actualizado exitosamente.');
}
public function destroy(Request $request, CarouselItem $carouselItem)
{
$this->checkGeneralAdmin($request);
if ($carouselItem->imagen) {
$imagePath = public_path($carouselItem->imagen);
if (File::exists($imagePath)) {
File::delete($imagePath);
}
}
$carouselItem->delete();
return redirect()->route('admin.carousel.index')->with('admin_msg', 'Slide eliminado exitosamente.');
}
}
@@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Categoria;
class CategoriaController extends Controller
{
private function checkSuperAdmin(Request $request)
{
if (!session('admin_logged_in') || session('admin_role') != 1) {
abort(403, 'Acceso denegado. Solo Súper Administradores.');
}
}
public function index(Request $request)
{
$this->checkSuperAdmin($request);
$categorias = Categoria::latest()->get();
return view('admin.categorias.index', compact('categorias'));
}
public function create(Request $request)
{
$this->checkSuperAdmin($request);
return view('admin.categorias.form', ['categoria' => null]);
}
public function store(Request $request)
{
$this->checkSuperAdmin($request);
$data = $request->validate([
'nombre' => 'required|string|max:50',
'edad_min' => 'required|integer',
'edad_max' => 'required|integer|gte:edad_min',
'genero' => 'nullable|string|max:20',
]);
$data['es_libre'] = $request->has('es_libre');
Categoria::create($data);
return redirect()->route('admin.categorias.index')->with('admin_msg', 'Categoría creada.');
}
public function edit(Request $request, $id)
{
$this->checkSuperAdmin($request);
$categoria = Categoria::findOrFail($id);
return view('admin.categorias.form', compact('categoria'));
}
public function update(Request $request, $id)
{
$this->checkSuperAdmin($request);
$categoria = Categoria::findOrFail($id);
$data = $request->validate([
'nombre' => 'required|string|max:50',
'edad_min' => 'required|integer',
'edad_max' => 'required|integer|gte:edad_min',
'genero' => 'nullable|string|max:20',
]);
$data['es_libre'] = $request->has('es_libre');
$categoria->update($data);
return redirect()->route('admin.categorias.index')->with('admin_msg', 'Categoría actualizada.');
}
public function destroy(Request $request, $id)
{
$this->checkSuperAdmin($request);
$categoria = Categoria::findOrFail($id);
$categoria->delete();
return redirect()->route('admin.categorias.index')->with('admin_msg', 'Categoría eliminada.');
}
}
@@ -0,0 +1,380 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Torneo;
use App\Services\FixtureService;
class FixtureController extends Controller
{
private FixtureService $fixtureService;
public function __construct(FixtureService $fixtureService)
{
$this->fixtureService = $fixtureService;
}
private function checkSuperAdmin()
{
if (!session('admin_logged_in') || session('admin_role') != 1) {
abort(403, 'Solo Súper Administradores pueden generar fixtures.');
}
}
/**
* POST /admin/torneos/{id}/generar-fixture — Preview del fixture
*/
public function preview(Request $request, int $id)
{
$this->checkSuperAdmin();
$torneo = Torneo::with('equipos.club')->findOrFail($id);
$request->validate([
'fecha_inicio' => 'required|date|after_or_equal:today',
'dias_entre_jornadas' => 'required|integer|min:1|max:60',
'sede_default' => 'nullable|string|max:200',
'doble_rueda' => 'nullable|boolean',
]);
try {
$partidos = $this->fixtureService->generarRoundRobin(
torneo: $torneo,
fechaInicio: $request->input('fecha_inicio'),
diasEntreJornadas: (int) $request->input('dias_entre_jornadas', 7),
sedeDefault: $request->input('sede_default', ''),
dobleRueda: (bool) $request->input('doble_rueda', false),
);
// Enriquecer con nombres para la vista
$partidosEnriquecidos = collect($partidos)->map(function ($p) {
$local = \App\Models\Equipo::with('club')->find($p['id_equipo_local']);
$visitante = \App\Models\Equipo::with('club')->find($p['id_equipo_visitante']);
return array_merge($p, [
'nombre_local' => ($local->club->nombre ?? '?') . ' (' . ($local->categoria ?? '') . ')',
'nombre_visitante' => ($visitante->club->nombre ?? '?') . ' (' . ($visitante->categoria ?? '') . ')',
]);
})->toArray();
} catch (\InvalidArgumentException $e) {
return back()->with('admin_error', $e->getMessage());
}
$fixtureParams = [
'fecha_inicio' => $request->input('fecha_inicio'),
'dias_entre_jornadas' => $request->input('dias_entre_jornadas', 7),
'sede_default' => $request->input('sede_default', ''),
'doble_rueda' => (bool) $request->input('doble_rueda', false),
];
return view('admin.torneos.fixture_preview', compact('torneo', 'partidosEnriquecidos', 'fixtureParams'));
}
/**
* POST /admin/torneos/{id}/confirmar-fixture — Persiste el fixture
*/
public function confirmar(Request $request, int $id)
{
$this->checkSuperAdmin();
$torneo = Torneo::with('equipos.club')->findOrFail($id);
$request->validate([
'fecha_inicio' => 'required|date',
'dias_entre_jornadas' => 'required|integer|min:1',
'sede_default' => 'nullable|string|max:200',
'doble_rueda' => 'nullable|boolean',
]);
try {
$partidos = $this->fixtureService->generarRoundRobin(
torneo: $torneo,
fechaInicio: $request->input('fecha_inicio'),
diasEntreJornadas: (int) $request->input('dias_entre_jornadas', 7),
sedeDefault: $request->input('sede_default', ''),
dobleRueda: (bool) $request->input('doble_rueda', false),
);
$creados = $this->fixtureService->persistirFixture($partidos, $torneo);
} catch (\InvalidArgumentException $e) {
return back()->with('admin_error', $e->getMessage());
}
return redirect()->route('admin.torneos.edit', $id)
->with('admin_msg', "✅ Fixture generado correctamente: {$creados} partidos creados.");
}
public function importForm(int $id)
{
$this->checkSuperAdmin();
$torneo = Torneo::findOrFail($id);
return view('admin.torneos.importar', compact('torneo'));
}
public function importStore(Request $request, int $id)
{
$this->checkSuperAdmin();
$torneo = Torneo::with(['equipos.club'])->findOrFail($id);
$request->validate([
'texto_importar' => 'required|string',
]);
$lineas = explode("\n", $request->input('texto_importar'));
$creados = 0;
$errores = [];
foreach ($lineas as $index => $linea) {
$linea = trim($linea);
if (empty($linea)) continue;
try {
// Formato esperado: Fecha, ClubL, CatL, ClubV, CatV, MarcadorL, MarcadorV, Sede, Grupo
$partes = str_getcsv($linea);
if (count($partes) < 7) {
throw new \Exception("Formato insuficiente. Se esperan al menos 7 columnas.");
}
$fechaRaw = trim($partes[0]);
$fecha = \Carbon\Carbon::parse(str_replace('/', '-', $fechaRaw))->format('Y-m-d');
$nombreClubL = trim($partes[1]);
$catL = trim($partes[2]);
$nombreClubV = trim($partes[3]);
$catV = trim($partes[4]);
$marcadorL = trim($partes[5]);
$marcadorV = trim($partes[6]);
$sede = $partes[7] ?? null;
$grupo = $partes[8] ?? null;
// Buscar equipos con validación de grupo (prioridad) y categoría
$equipoL = $this->buscarEquipo($nombreClubL, $catL, $torneo, $grupo);
$equipoV = $this->buscarEquipo($nombreClubV, $catV, $torneo, $grupo);
if (!$equipoL || !$equipoV) {
$missing = !$equipoL ? "'{$nombreClubL} ({$catL})'" : "'{$nombreClubV} ({$catV})'";
throw new \Exception("No se encontró el equipo {$missing} en el grupo '" . ($grupo ?? 'N/A') . "' ni por categoría.");
}
\App\Models\Evento::create([
'id_evento' => uniqid('ev_imp_'),
'id_torneo' => $id,
'fase' => \App\Models\Evento::FASE_REGULAR,
'fecha_evento' => $fecha,
'id_equipo_local' => $equipoL->id_equipo,
'id_equipo_visitante' => $equipoV->id_equipo,
'marcador_local' => $marcadorL !== '' ? (int)$marcadorL : null,
'marcador_visitante' => $marcadorV !== '' ? (int)$marcadorV : null,
'nombre_evento' => $equipoL->club->nombre . ' vs ' . $equipoV->club->nombre,
'hora_inicio' => '19:00:00',
'hora_fin' => '21:00:00',
'sede' => $sede,
'precio' => 0,
]);
$creados++;
} catch (\Exception $e) {
$errores[] = "Línea " . ($index + 1) . ": " . $e->getMessage();
continue;
}
}
$msg = "Se importaron {$creados} partidos exitosamente.";
if (count($errores) > 0) {
return back()->with('admin_msg', $msg)->with('admin_error', "Se detectaron errores en " . count($errores) . " líneas:<br>" . implode("<br>", $errores));
}
return redirect()->route('admin.torneos.edit', $id)->with('admin_msg', $msg);
}
private function buscarEquipo(string $clubName, string $category, Torneo $torneo, ?string $grupo = null)
{
$clubNameNorm = $this->normalizeString($clubName);
$categoryNorm = $this->normalizeString($category);
$grupoNorm = $grupo ? $this->normalizeString($grupo) : null;
// PASO 1: Prioridad absoluta al GRUPO (vía pivot)
if ($grupoNorm) {
$match = $torneo->equipos->first(function($e) use ($clubNameNorm, $grupoNorm) {
$eClubName = $this->normalizeString($e->club->nombre ?? '');
$eGrupo = $this->normalizeString($e->pivot->grupo ?? '');
return ($eGrupo === $grupoNorm) &&
(strpos($eClubName, $clubNameNorm) !== false || strpos($clubNameNorm, $eClubName) !== false);
});
if ($match) return $match;
}
// PASO 2: Fallback a búsqueda por CATEGORÍA si el grupo no coincide o no se especificó
return $torneo->equipos->first(function($e) use ($clubNameNorm, $categoryNorm) {
$eClubName = $this->normalizeString($e->club->nombre ?? '');
$eCategory = $this->normalizeString($e->categoria ?? '');
$matchClub = (strpos($eClubName, $clubNameNorm) !== false || strpos($clubNameNorm, $eClubName) !== false);
$matchCat = (strpos($eCategory, $categoryNorm) !== false || strpos($categoryNorm, $eCategory) !== false);
return $matchClub && $matchCat;
});
}
private function normalizeString(?string $str): string
{
if (!$str) return '';
$str = mb_strtolower(trim($str), 'UTF-8');
$str = str_replace(
['á', 'é', 'í', 'ó', 'ú', 'ü', 'ñ'],
['a', 'e', 'i', 'o', 'u', 'u', 'n'],
$str
);
// Eliminar caracteres no alfanuméricos para un matching más flexible
return preg_replace('/[^a-z0-9]/', '', $str);
}
public function generarPlayoffs(Request $request, int $id)
{
$this->checkSuperAdmin();
$torneo = Torneo::findOrFail($id);
$grupo = $request->input('grupo');
$formato = (int) $request->input('formato', 1); // 1, 3, 5
if (!$grupo) {
return back()->with('admin_error', 'Debes seleccionar un grupo para generar los playoffs.');
}
$ts = new \App\Services\TournamentService();
$standings = $ts->getStandings($id, true);
if (!isset($standings[$grupo])) {
return back()->with('admin_error', "No hay equipos en el grupo {$grupo}.");
}
$top8 = array_slice($standings[$grupo], 0, 8);
if (count($top8) < 2) {
return back()->with('admin_error', "Se necesitan al menos 2 equipos para generar playoffs.");
}
// Determinar emparejamientos (1 vs 8, 4 vs 5, 2 vs 7, 3 vs 6)
// Usamos el seeding oficial: 1v8, 4v5, 2v7, 3v6
$parejas = [
['local' => $top8[0]['id'], 'visit' => $top8[7]['id'] ?? null, 'nro' => 1],
['local' => $top8[3]['id'] ?? null, 'visit' => $top8[4]['id'] ?? null, 'nro' => 2],
['local' => $top8[1]['id'] ?? null, 'visit' => $top8[6]['id'] ?? null, 'nro' => 3],
['local' => $top8[2]['id'] ?? null, 'visit' => $top8[5]['id'] ?? null, 'nro' => 4],
];
$count = 0;
foreach ($parejas as $p) {
if (!$p['local'] || !$p['visit']) continue;
$local = \App\Models\Equipo::with('club')->find($p['local']);
$visit = \App\Models\Equipo::with('club')->find($p['visit']);
// Crear N partidos según el formato
for ($i = 0; $i < $formato; $i++) {
\App\Models\Evento::create([
'id_evento' => uniqid('ply_'),
'id_torneo' => $id,
'fase' => \App\Models\Evento::FASE_CUARTOS,
'numero_partido_bracket' => $p['nro'],
'id_equipo_local' => $p['local'],
'id_equipo_visitante' => $p['visit'],
'nombre_evento' => "4tos (J".($i+1)."): " . $local->club->nombre . " vs " . $visit->club->nombre . " ({$grupo})",
'fecha_evento' => now()->addDays(7 + ($i * 3))->format('Y-m-d'),
'hora_inicio' => '20:00:00',
'hora_fin' => '22:00:00',
'precio' => 0,
]);
$count++;
}
}
return redirect()->route('admin.torneos.playoffs.manage', $id)
->with('admin_msg', "Playoffs generados: {$count} partidos creados para el grupo {$grupo}.");
}
public function managePlayoffs(int $id)
{
$this->checkSuperAdmin();
$torneo = Torneo::findOrFail($id);
$ts = new \App\Services\TournamentService();
$bracket = $ts->getPlayoffBrackets($id);
$grupos = \DB::table('torneo_equipo')->where('id_torneo', $id)->distinct()->pluck('grupo')->filter();
return view('admin.torneos.playoff_manage', compact('torneo', 'bracket', 'grupos'));
}
public function avanzarGanador(Request $request, int $id)
{
$this->checkSuperAdmin();
$faseActual = (int) $request->input('fase');
$nroBracket = (int) $request->input('nro_bracket');
$idGanador = (int) $request->input('id_ganador');
$torneo = Torneo::findOrFail($id);
$ganador = \App\Models\Equipo::with('club')->findOrFail($idGanador);
// Mapeo de avance
// Cuartos 1 & 2 -> Semis 1
// Cuartos 3 & 4 -> Semis 2
// Semis 1 & 2 -> Final 1
$mapping = [
\App\Models\Evento::FASE_CUARTOS => [
1 => ['next_fase' => \App\Models\Evento::FASE_SEMIS, 'next_nro' => 1, 'side' => 'local'],
2 => ['next_fase' => \App\Models\Evento::FASE_SEMIS, 'next_nro' => 1, 'side' => 'visitante'],
3 => ['next_fase' => \App\Models\Evento::FASE_SEMIS, 'next_nro' => 2, 'side' => 'local'],
4 => ['next_fase' => \App\Models\Evento::FASE_SEMIS, 'next_nro' => 2, 'side' => 'visitante'],
],
\App\Models\Evento::FASE_SEMIS => [
1 => ['next_fase' => \App\Models\Evento::FASE_FINAL, 'next_nro' => 1, 'side' => 'local'],
2 => ['next_fase' => \App\Models\Evento::FASE_FINAL, 'next_nro' => 1, 'side' => 'visitante'],
]
];
if (!isset($mapping[$faseActual][$nroBracket])) {
return back()->with('admin_error', 'No se puede avanzar desde esta fase.');
}
$next = $mapping[$faseActual][$nroBracket];
// Buscar si ya existe el partido en la siguiente fase
$eventoNext = \App\Models\Evento::where('id_torneo', $id)
->where('fase', $next['next_fase'])
->where('numero_partido_bracket', $next['next_nro'])
->first();
if ($eventoNext) {
if ($next['side'] == 'local') {
$eventoNext->id_equipo_local = $idGanador;
} else {
$eventoNext->id_equipo_visitante = $idGanador;
}
$eventoNext->nombre_evento = ($eventoNext->equipoLocal->club->nombre ?? 'TBD') . ' vs ' . ($eventoNext->equipoVisitante->club->nombre ?? 'TBD');
$eventoNext->save();
} else {
// Crear el primer partido de la serie (por defecto 1 partido, el admin puede agregar más)
\App\Models\Evento::create([
'id_evento' => uniqid('ply_adv_'),
'id_torneo' => $id,
'fase' => $next['next_fase'],
'numero_partido_bracket' => $next['next_nro'],
'id_equipo_local' => $next['side'] == 'local' ? $idGanador : null,
'id_equipo_visitante' => $next['side'] == 'visitante' ? $idGanador : null,
'nombre_evento' => $next['side'] == 'local' ? ($ganador->club->nombre . " vs TBD") : ("TBD vs " . $ganador->club->nombre),
'fecha_evento' => now()->addDays(14)->format('Y-m-d'),
'hora_inicio' => '20:00:00',
'hora_fin' => '22:00:00',
'precio' => 0,
]);
}
return back()->with('admin_msg', "✅ Equipo {$ganador->club->nombre} avanzado a la siguiente ronda.");
}
}
@@ -0,0 +1,129 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Pase;
use App\Models\Jugador;
use App\Models\Club;
class PaseController extends Controller
{
private function checkGeneralAdmin(Request $request)
{
if (!session('admin_logged_in') || !in_array(session('admin_role'), [1, 2])) {
abort(403, 'Acceso denegado');
}
}
private function checkSuperAdmin(Request $request)
{
if (!session('admin_logged_in') || session('admin_role') != 1) {
abort(403, 'Acceso denegado. Solo Súper Administradores.');
}
}
public function index(Request $request)
{
$this->checkGeneralAdmin($request);
$query = Pase::with(['jugador', 'clubOrigen', 'clubDestino']);
if (session('admin_role') == 2) {
$idClub = session('admin_id_club');
$query->where(function ($q) use ($idClub) {
$q->where('id_club_origen', $idClub)
->orWhere('id_club_destino', $idClub);
});
}
$pases = $query->orderBy('created_at', 'desc')->paginate(20);
return view('admin.pases.index', compact('pases'));
}
public function create(Request $request)
{
$this->checkGeneralAdmin($request);
return view('admin.pases.create');
}
public function store(Request $request)
{
$this->checkGeneralAdmin($request);
$request->validate([
'documento' => 'required|string|exists:jugadores,documento'
], [
'documento.exists' => 'No se encontró un jugador con ese DNI.'
]);
$jugador = Jugador::where('documento', $request->documento)->first();
// Si el jugador ya pertenece al club destino, error
$idClubDestino = session('admin_role') == 2 ? session('admin_id_club') : $request->input('id_club_destino');
if (!$idClubDestino) {
return back()->withErrors(['id_club_destino' => 'Debe especificar el club destino.']);
}
if ($jugador->id_club_actual == $idClubDestino) {
return back()->withErrors(['documento' => 'Este jugador ya pertenece a tu club.']);
}
// Crear la petición de pase
Pase::create([
'id_jugador' => $jugador->id_jugador,
'id_club_origen' => $jugador->id_club_actual,
'id_club_destino' => $idClubDestino,
'estado' => 'Pendiente'
]);
return redirect()->route('admin.pases.index')->with('admin_msg', 'Solicitud de pase creada correctamente y está pendiente de aprobación.');
}
public function aprobar(Request $request, $id)
{
$this->checkSuperAdmin($request);
$pase = Pase::findOrFail($id);
if ($pase->estado !== 'Pendiente') {
return back()->withErrors(['pase' => 'Este pase ya fue procesado.']);
}
$pase->update(['estado' => 'Aprobado']);
// Actualizar jugador
if ($pase->jugador) {
// Desvincular de equipos del club de origen
$equiposOldClubIds = $pase->jugador->equipos()
->where('id_club', $pase->id_club_origen)
->pluck('equipos.id_equipo');
if ($equiposOldClubIds->count() > 0) {
$pase->jugador->equipos()->detach($equiposOldClubIds);
}
$pase->jugador->update([
'id_club_origen' => $pase->id_club_origen,
'id_club_actual' => $pase->id_club_destino
]);
}
return redirect()->route('admin.pases.index')->with('admin_msg', 'Pase aprobado correctamente y jugador desvinculado de equipos anteriores.');
}
public function rechazar(Request $request, $id)
{
$this->checkSuperAdmin($request);
$pase = Pase::findOrFail($id);
if ($pase->estado !== 'Pendiente') {
return back()->withErrors(['pase' => 'Este pase ya fue procesado.']);
}
$pase->update(['estado' => 'Rechazado']);
return redirect()->route('admin.pases.index')->with('admin_msg', 'Pase rechazado.');
}
}