diff --git a/app/Exports/ChoferesExport.php b/app/Exports/ChoferesExport.php new file mode 100644 index 0000000..cb9f25a --- /dev/null +++ b/app/Exports/ChoferesExport.php @@ -0,0 +1,24 @@ +get(); + } + + public function headings(): array + { + return [ + 'ID', + 'Nombre', + 'Tipo de Licencia', + ]; + } +} diff --git a/app/Exports/UsuariosExport.php b/app/Exports/UsuariosExport.php index f7b83e5..f73f6f9 100644 --- a/app/Exports/UsuariosExport.php +++ b/app/Exports/UsuariosExport.php @@ -10,23 +10,37 @@ class UsuariosExport implements FromCollection, WithHeadings { public function collection() { - return User::select( 'name', 'email','apellido', - 'puesto', - 'carrera', - 'telefono',)->get(); + $usuarios = User::with(['puesto', 'tipo', 'departamento'])->get(); + + $data = []; + $contador = 1; + foreach ($usuarios as $usuario) { + $data[] = [ + 'No.' => $contador++, + 'Nombre' => $usuario->name, + 'Correo' => $usuario->email, + 'Apellido' => $usuario->apellido, + 'Puesto' => $usuario->puesto->nombre ?? '', + 'Tipo' => $usuario->tipo->nombre ?? '', + 'Departamento' => $usuario->departamento->departamento ?? '', + 'Teléfono' => $usuario->telefono, + ]; + } + + return collect($data); } public function headings(): array { return [ - 'nombre', - 'correo', - 'apellido', - 'puesto', - 'carrera', - 'telefono', - 'Fecha de Creación', - 'Última Actualización' + 'No.', + 'Nombre', + 'Correo', + 'Apellido', + 'Puesto', + 'Tipo', + 'Departamento', + 'Teléfono', ]; } } diff --git a/app/Exports/puestosExport.php b/app/Exports/puestosExport.php new file mode 100644 index 0000000..54f3270 --- /dev/null +++ b/app/Exports/puestosExport.php @@ -0,0 +1,44 @@ +puestos = $puestos; + } + + public function collection() + { + // Obtén los puestos + $puestos = $this->puestos ?: Puesto::where('eliminado', 0)->get(['nombre']); + + // Construye la colección con número consecutivo + $data = []; + $contador = 1; + foreach ($puestos as $puesto) { + $data[] = [ + 'ID' => $contador++, + 'Nombre del Puesto' => $puesto->nombre, + ]; + } + + return collect($data); + } + + public function headings(): array + { + return [ + 'ID', + 'Nombre del Puesto', + ]; + } +} diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php new file mode 100644 index 0000000..6d39e23 --- /dev/null +++ b/app/Http/Controllers/AdminController.php @@ -0,0 +1,13 @@ +middleware('auth')->only('logout'); } - protected function authenticated(Request $request, $user) + protected function authenticated($request, $user) { - if ($user->rol === 'mantenimiento') { - return redirect('/maintenance'); + if ($user->tipos_id == 1) { + return redirect('/dashboard'); + } elseif ($user->tipos_id == 2) { + return redirect('/user-dashboard'); + } else { + return redirect('/home'); } - return redirect('/dashboard'); } } diff --git a/app/Http/Controllers/ChoferController.php b/app/Http/Controllers/ChoferController.php new file mode 100644 index 0000000..94fd693 --- /dev/null +++ b/app/Http/Controllers/ChoferController.php @@ -0,0 +1,97 @@ + null]); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $request->validate([ + 'nombre' => 'required|string|max:255', + 'tipo_licencia' => 'required|string|max:255', + ]); + + Chofer::create($request->all()); + return redirect()->route('choferes.index')->with('success', 'Chofer creado exitosamente.'); + } + + /** + * Display the specified resource. + */ + public function show(Chofer $chofer) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit($id) + { + $chofer = Chofer::findOrFail($id); + return view('choferesCrearEditar', compact('chofer')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, $id) + { + $request->validate([ + 'nombre' => 'required|string|max:255', + 'tipo_licencia' => 'required|string|max:255', + ]); + + $chofer = Chofer::findOrFail($id); + $chofer->update($request->all()); + return redirect()->route('choferes.index')->with('success', 'Chofer actualizado exitosamente.'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy($id) + { + $chofer = Chofer::findOrFail($id); + $chofer->delete(); + return redirect()->route('choferes.index')->with('success', 'Chofer eliminado exitosamente.'); + } + + public function exportExcel() + { + return \Maatwebsite\Excel\Facades\Excel::download(new \App\Exports\ChoferesExport, 'choferes.xlsx'); + } + + public function exportPDF() + { + $choferes = \App\Models\Chofer::all(); + $pdf = \PDF::loadView('exports.choferes-pdf', ['choferes' => $choferes]); + return $pdf->download('choferes.pdf'); + } +} diff --git a/app/Http/Controllers/DespartamentoController.php b/app/Http/Controllers/DespartamentoController.php new file mode 100644 index 0000000..97fd10c --- /dev/null +++ b/app/Http/Controllers/DespartamentoController.php @@ -0,0 +1,129 @@ +busqueda; + + if ($busqueda) { + // Busca en la columna 'nombre' de la tabla 'despartamentos' + $despartamentos = despartamento::where('nombre', 'LIKE', "%{$busqueda}%")->where('eliminado', 0)->get(); + + if ($despartamentos->isEmpty()) { + return redirect()->route('despartamento.index') + ->with('error', 'No existe ningún departamento con el nombre "' . $busqueda . '". Por favor, inténtalo de nuevo.'); + } + } else { + // Si no hay búsqueda, mostrar todos los departamentos + $despartamentos = despartamento::where('eliminado', 0)->get(); + } + + return view('despartamentos', ['despartamentos' => $despartamentos]); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + return view('despartamentosCrearEditar', ['despartamento' => null]); // No se necesita pasar departamentos + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + // Valida la entrada + $request->validate([ + 'departamento' => 'required|string|max:255|unique:despartamentos,departamento', // Asegúrate de que 'departamento' sea único + ], [ + 'departamento.required' => 'El campo departamento es obligatorio.', + 'departamento.string' => 'El campo departamento debe ser una cadena de texto.', + 'departamento.max' => 'El campo departamento no puede tener más de 255 caracteres.', + 'departamento.unique' => 'Ya existe un departamento con ese nombre.', + ]); + + // Crea un nuevo departamento + $despartamento = new despartamento(); + $despartamento->departamento = $request->departamento; // Asigna el nombre ingresado por el usuario + $despartamento->eliminado = 0; // Departamento como activo por defecto + $despartamento->save(); + + return redirect()->route('despartamentos.index')->with('success', 'Departamento creado exitosamente.'); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit($id) + { + $despartamento = despartamento::findOrFail($id); // Busca el departamento por ID + return view('despartamentosCrearEditar', ['despartamento' => $despartamento]); // Pasa el departamento a la vista + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, $id) + { + $request->validate([ + 'departamento' => 'required|string|max:255|unique:despartamentos,departamento', // Asegúrate de que 'departamento' sea único + ], [ + 'departamento.required' => 'El campo departamento es obligatorio.', + 'departamento.string' => 'El campo departamento debe ser una cadena de texto.', + 'departamento.max' => 'El campo departamento no puede tener más de 255 caracteres.', + 'departamento.unique' => 'Ya existe un departamento con ese nombre, por favor elige otro.', + ]); + + $despartamento = despartamento::findOrFail($id); // Encuentra el departamento por ID + + // Verifica si el nombre del departamento ha cambiado + if ($despartamento->departamento !== $request->departamento) { + $despartamento->departamento = $request->departamento; // Actualiza el nombre del departamento + } + + $despartamento->eliminado = 0; // Cambia el estado a activo si se está editando + $despartamento->save(); // Guarda los cambios + + return redirect()->route('despartamentos.index')->with('success', 'Departamento actualizado correctamente.'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy($id) + { + $despartamento = despartamento::findOrFail($id); + \App\Models\User::where('departamento_id', $id)->update(['departamento_id' => null]); + $despartamento->eliminado = 1; + $despartamento->save(); + + return redirect()->route('despartamentos.index') + ->with('success', 'Departamento eliminado exitosamente. Los usuarios afectados necesitan ser reasignados.'); + } + + public function exportExcel() + { + return Excel::download(new DespartamentosExport, 'despartamentos.xlsx'); + } + + public function exportPDF() + { + $departamentos = despartamento::where('eliminado', 0)->get(); + $pdf = PDF::loadView('exports.departamentos', ['departamentos' => $departamentos]); + return $pdf->download('departamentos.pdf'); + } +} diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 8c90f0f..8e6bbb9 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -23,8 +23,36 @@ class HomeController extends Controller */ public function index() { + $user = auth()->user(); - return view('dashboard'); + // Validar que el usuario tenga tipo asignado y que sea Administrador o Servicios Generales + if (!$user->tipo || !in_array($user->tipos_id, [1, 4])) { + // Cerrar la sesión del usuario + auth()->logout(); + // Redirigir con mensaje de error + return redirect()->route('login')->with('error', 'No tienes permisos para acceder al sistema. Solo los administradores o servicios pueden acceder en este momento.'); + } + // Notificaciones si el usuario no tiene puesto o departamento asignado + $notificaciones = []; + if (is_null($user->puesto_id)) { + $notificaciones[] = 'No tienes un puesto asignado. Contacta al administrador para que te asigne uno.'; + } + if (is_null($user->departamento_id)) { + $notificaciones[] = 'No tienes un departamento asignado. Contacta al administrador para que te asigne uno.'; + } + + // Si es administrador, mostrar el dashboard con datos reales + $adminData = [ + 'totalUsers' => \App\Models\User::where('eliminado', 0)->count(), + 'totalPrestamos' => \App\Models\Prestamo::count(), + 'prestamosPendientes' => \App\Models\Prestamo::where('estado', 'pendiente')->count(), + 'prestamosAceptados' => \App\Models\Prestamo::where('estado', 'aceptado')->count(), + ]; + + return view('dashboard', [ + 'adminData' => $adminData, + 'notificaciones' => $notificaciones + ]); } } diff --git a/app/Http/Controllers/PrestamoController.php b/app/Http/Controllers/PrestamoController.php index e31dbdb..966a3e1 100644 --- a/app/Http/Controllers/PrestamoController.php +++ b/app/Http/Controllers/PrestamoController.php @@ -43,7 +43,13 @@ class PrestamoController extends Controller */ public function create() { - return view('prestamosCrearEditar', ['prestamo' => null]); // No se necesita pasar préstamos + $vehiculos = \App\Models\tiposVeiculos::where('status', true)->get(); + $choferes = \App\Models\Chofer::all(); + return view('prestamosCrearEditar', [ + 'prestamo' => null, + 'vehiculos' => $vehiculos, + 'choferes' => $choferes + ]); } /** @@ -54,28 +60,28 @@ class PrestamoController extends Controller // Validación de datos $request->validate([ 'nombre_solicitante' => 'required|string|max:255', + 'chofer_id' => 'required|exists:choferes,id', 'destino' => 'required|string|max:255', 'fecha_hora_salida' => 'required|date', 'fecha_hora_llegada' => 'required|date', 'motivo' => 'required|string|max:255', 'domicilio' => 'required|string|max:255', 'numero_personas' => 'required|integer', + 'vehiculo_id' => 'required|exists:tipos_veiculos,id' ]); - // Crea un nuevo préstamo - $prestamo = new Prestamo(); - $prestamo->nombre_solicitante = $request->nombre_solicitante; - $prestamo->destino = $request->destino; - $prestamo->fecha_hora_salida = $request->fecha_hora_salida; - $prestamo->fecha_hora_llegada = $request->fecha_hora_llegada; - $prestamo->motivo = $request->motivo; - $prestamo->domicilio = $request->domicilio; - $prestamo->numero_personas = $request->numero_personas; - $prestamo->chofer = $request->has('chofer') ? 1 : 0; // Manejo del checkbox - $prestamo->eliminado = 0; // Marca como activo por defecto + // Preparar los datos + $datos = $request->all(); + $datos['chofer'] = $request->has('chofer') ? 1 : 0; + // Sobrescribir el nombre del solicitante con el nombre del usuario autenticado + $datos['nombre_solicitante'] = auth()->user()->name; + + $prestamo = new Prestamo($datos); + $prestamo->estado = 'pendiente'; $prestamo->save(); - return redirect()->route('prestamos.index')->with('success', 'Préstamo creado exitosamente.'); + return redirect()->route('prestamos.index') + ->with('success', 'Préstamo solicitado correctamente. Esperando aprobación.'); } /** @@ -84,7 +90,13 @@ class PrestamoController extends Controller public function edit($id) { $prestamo = Prestamo::findOrFail($id); // Busca el préstamo por ID - return view('prestamosCrearEditar', ['prestamo' => $prestamo]); // Pasa el préstamo a la vista + $vehiculos = \App\Models\tiposVeiculos::where('status', true)->get(); + $choferes = \App\Models\Chofer::all(); + return view('prestamosCrearEditar', [ + 'prestamo' => $prestamo, + 'vehiculos' => $vehiculos, + 'choferes' => $choferes + ]); // Pasa el préstamo a la vista } /** @@ -143,9 +155,9 @@ class PrestamoController extends Controller */ public function exportPDF() { - $prestamos = Prestamo::where('eliminado', 0)->get(); - $pdf = PDF::loadView('exports.prestamos-pdf', ['prestamos' => $prestamos]); - return $pdf->download('prestamos.pdf'); + $prestamos = \App\Models\Prestamo::with(['vehiculo', 'choferAsignado'])->get(); + $pdf = \PDF::loadView('exports.prestamos-reporte-pdf', ['prestamos' => $prestamos]); + return $pdf->download('reporte_general_prestamos.pdf'); } public function aceptados(Request $request) @@ -190,4 +202,35 @@ class PrestamoController extends Controller return redirect()->route('prestamos.index') ->with('success', 'Préstamo rechazado exitosamente.'); } + + public function show($id) + { + $prestamo = \App\Models\Prestamo::findOrFail($id); + return view('prestamos.show', compact('prestamo')); + } + + public function pendientes() + { + $prestamos = \App\Models\Prestamo::where('estado', 'pendiente')->where('eliminado', 0)->get(); + return view('prestamos.pendientes', compact('prestamos')); + } + + public function rechazados(Request $request) + { + $busqueda = $request->busqueda; + + $prestamos = \App\Models\Prestamo::where('estado', 'rechazado') + ->where('eliminado', 0) + ->when($busqueda, function($query) use ($busqueda) { + $query->where(function($q) use ($busqueda) { + $q->where('nombre_solicitante', 'LIKE', "%{$busqueda}%") + ->orWhere('destino', 'LIKE', "%{$busqueda}%") + ->orWhere('motivo', 'LIKE', "%{$busqueda}%"); + }); + }) + ->orderBy('created_at', 'desc') + ->get(); + + return view('prestamos.rechazados', compact('prestamos')); + } } diff --git a/app/Http/Controllers/PuestoController.php b/app/Http/Controllers/PuestoController.php new file mode 100644 index 0000000..2268cba --- /dev/null +++ b/app/Http/Controllers/PuestoController.php @@ -0,0 +1,128 @@ +busqueda; + + if ($busqueda) { + $puestos = Puesto::where('nombre', 'LIKE', "%{$busqueda}%") + ->where('eliminado', 0) + ->get(); + + if ($puestos->isEmpty()) { + return redirect()->route('puestos.index') + ->with('error', 'No existe ningún puesto con el nombre "' . $busqueda . '". Por favor, inténtalo de nuevo.'); + } + } else { + $puestos = Puesto::where('eliminado', 0)->get(); + } + + return view('puestos', ['puestos' => $puestos]); + } + + public function create() + { + return view('puestosCrearEditar', ['puesto' => null]); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'nombre' => ['required', 'string', 'max:255'], + ], [ + 'nombre.required' => 'El campo nombre es obligatorio.', + 'nombre.string' => 'El campo nombre debe ser una cadena de texto.', + 'nombre.max' => 'El campo nombre no debe exceder 255 caracteres.', + ]); + $puesto = new Puesto($validated); + $puesto->eliminado = 0; + $puesto->save(); + + return redirect()->route('puestos.index') + ->with('success', 'Puesto creado exitosamente'); + } + + + public function edit($id) + { + $puesto = Puesto::findOrFail($id); + return view('puestosCrearEditar', ['puesto' => $puesto]); + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'nombre' => ['required', 'string', 'max:255'], + ], [ + 'nombre.required' => 'El campo nombre es obligatorio.', + 'nombre.string' => 'El campo nombre debe ser una cadena de texto.', + 'nombre.max' => 'El campo nombre no debe exceder 255 caracteres.', + ]); + + $puesto = Puesto::findOrFail($id); + $puesto->update($validated); + + return redirect()->route('puestos.index') + ->with('success', 'Puesto actualizado exitosamente'); + } + + public function destroy($id) + { + $puesto = Puesto::findOrFail($id); + \App\Models\User::where('puesto_id', $id)->update(['puesto_id' => null]); + $puesto->eliminado = 1; + $puesto->save(); + + return redirect()->route('puestos.index') + ->with('success', 'Puesto eliminado exitosamente. Los usuarios afectados necesitan ser reasignados.'); + } + + public function exportExcel() + { + return Excel::download(new PuestosExport, 'puestos.xlsx'); + } + + public function exportPDF() + { + $puestos = Puesto::where('eliminado', 0)->get(); + $pdf = PDF::loadView('exports.puestos', ['puestos' => $puestos]); + return $pdf->download('puestos.pdf'); + } + + public function export($format) + { + $puestos = Puesto::where('eliminado', 0) + ->orderBy('updated_at', 'desc') + ->get(); + + switch($format) { + case 'excel': + return Excel::download(new PuestosExport($puestos), 'puestos.xlsx'); + case 'pdf': + $pdf = PDF::loadView('exports.puestos', ['puestos' => $puestos]); + return $pdf->download('puestos.pdf'); + default: + return redirect()->back()->with('error', 'Formato no soportado'); + } + } + + public function toggleStatus($id) + { + $puesto = Puesto::findOrFail($id); + $puesto->eliminado = !$puesto->eliminado; + $puesto->save(); + + return redirect()->route('puestos.index') + ->with('success', 'Estado del puesto actualizado correctamente'); + } +} diff --git a/app/Http/Controllers/SolicitudVehiculoController.php b/app/Http/Controllers/SolicitudVehiculoController.php new file mode 100644 index 0000000..0e0111b --- /dev/null +++ b/app/Http/Controllers/SolicitudVehiculoController.php @@ -0,0 +1,49 @@ +middleware(['auth', 'profesor']); + } + + public function index() + { + $solicitudes = SolicitudVehiculo::where('user_id', auth()->id())->get(); + return view('profesor.solicitudes.index', compact('solicitudes')); + } + + public function create() + { + return view('profesor.solicitudes.create'); + } + + public function store(Request $request) + { + $request->validate([ + 'fecha_solicitud' => 'required|date', + 'hora_salida' => 'required', + 'hora_regreso' => 'required', + 'destino' => 'required|string', + 'motivo' => 'required|string', + ]); + + $solicitud = new SolicitudVehiculo(); + $solicitud->user_id = auth()->id(); + $solicitud->fecha_solicitud = $request->fecha_solicitud; + $solicitud->hora_salida = $request->hora_salida; + $solicitud->hora_regreso = $request->hora_regreso; + $solicitud->destino = $request->destino; + $solicitud->motivo = $request->motivo; + $solicitud->estado = 'pendiente'; + $solicitud->save(); + + return redirect()->route('profesor.solicitudes.index') + ->with('success', 'Solicitud creada exitosamente'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/TipoController.php b/app/Http/Controllers/TipoController.php new file mode 100644 index 0000000..8f8bf32 --- /dev/null +++ b/app/Http/Controllers/TipoController.php @@ -0,0 +1,65 @@ +tipoLicencia) - ->where('eliminado', 1) - ->exists(); - - if ($existe) { - return redirect()->route('tiposLicencias.create') - ->with('error', 'Ya existe un tipo de licencia con el nombre "' . $request->tipoLicencia . '". Por favor, ingrese un nombre diferente.') - ->withInput(); - } - $tipoLicencia = new TiposLicencias(); $tipoLicencia->tipoLicencia = $request->tipoLicencia; $tipoLicencia->eliminado = 1; @@ -92,18 +81,6 @@ class TiposLicenciasController extends Controller */ public function update(Request $request, $id) { - // Verificar si ya existe otro tipo de licencia con el mismo nombre - $existe = tiposLicencias::where('tipoLicencia', $request->tipoLicencia) - ->where('id', '!=', $id) - ->where('eliminado', 1) - ->exists(); - - if ($existe) { - return redirect()->route('tiposLicencias.edit', $id) - ->with('error', 'Ya existe un tipo de licencia con el nombre "' . $request->tipoLicencia . '". Por favor, ingrese un nombre diferente.') - ->withInput(); - } - $tipoLicencia = TiposLicencias::findOrFail($id); $tipoLicencia->tipoLicencia = $request->tipoLicencia; if ($request->has('eliminado')) { diff --git a/app/Http/Controllers/UserDashboardController.php b/app/Http/Controllers/UserDashboardController.php new file mode 100644 index 0000000..a58ee9c --- /dev/null +++ b/app/Http/Controllers/UserDashboardController.php @@ -0,0 +1,54 @@ +middleware('auth'); + } + + public function index() + { + // Permitir acceso solo a tipo 2 (Usuario normal) + if (auth()->user()->tipos_id != 2) { + return redirect('/')->with('error', 'No tienes permiso para acceder a esta sección'); + } + + return view('user-dashboard.index'); + } + + public function prestamosAceptados() + { + // Mostrar todos los préstamos aceptados a cualquier usuario tipo 2 + $prestamos = Prestamo::where('estado', 'aceptado')->with('choferAsignado')->get(); + + return view('user-dashboard.prestamos-aceptados', compact('prestamos')); + } + + public function detallePrestamo($id) + { + $prestamo = Prestamo::findOrFail($id); + return view('user-dashboard.detalle-prestamo', compact('prestamo')); + } + + public function cuestionario(Request $request) + { + $prestamo = null; + if ($request->has('prestamo_id')) { + $prestamo = \App\Models\Prestamo::find($request->prestamo_id); + } + return view('user-dashboard.cuestionario', compact('prestamo')); + } + + public function pdfPrestamo($id) + { + $prestamo = \App\Models\Prestamo::with('choferAsignado')->findOrFail($id); + $pdf = \PDF::loadView('exports.prestamo-individual-pdf', compact('prestamo')); + return $pdf->download('reporte_prestamo_'.$prestamo->id.'.pdf'); + } +} diff --git a/app/Http/Controllers/usuariosController.php b/app/Http/Controllers/usuariosController.php index 0a332bf..7c60b9d 100644 --- a/app/Http/Controllers/usuariosController.php +++ b/app/Http/Controllers/usuariosController.php @@ -8,6 +8,8 @@ use App\Exports\UsuariosExport; use Maatwebsite\Excel\Facades\Excel; use PDF; // Asegúrate de incluir la clase PDF use App\Models\Puesto; +use App\Models\Despartamento; +use App\Models\Tipo; class usuariosController extends Controller { @@ -39,8 +41,10 @@ class usuariosController extends Controller */ public function create() { + $tipos = Tipo::all(); + $despartamentos = Despartamento::all(); $puestos = Puesto::all(); - return view('usuariosCrearEditar', ['usuario' => null, 'puestos' => $puestos]); + return view('usuariosCrearEditar', ['usuario' => null, 'puestos' => $puestos, 'despartamentos'=> $despartamentos, 'tipos' => $tipos]); } @@ -49,26 +53,66 @@ class usuariosController extends Controller */ public function store(Request $request) { - // Validación de datos + // Validación de datos en español $request->validate([ - 'name' => 'required|string|max:255', - 'email' => 'required|string|email|max:255|unique:users', - 'apellido' => 'required|string|max:255', - 'puesto_id' => 'required|exists:puestos,id', - 'carrera' => 'required|string|max:255', - 'telefono' => 'required|string|max:255', - 'password' => 'required|string|min:8|confirmed', + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], + 'apellido' => ['required', 'string', 'max:255'], + 'tipos_id' => ['required', 'exists:tipos,id'], + 'puesto_id' => ['required', 'exists:puestos,id'], + 'departamento_id' => ['required', 'exists:despartamentos,id'], + 'telefono' => ['required', 'string', 'max:255'], + 'password' => ['required', 'string', 'min:8', 'confirmed'], + ], [ + 'name.required' => 'El campo nombre es obligatorio.', + 'name.string' => 'El campo nombre debe ser una cadena de texto.', + 'name.max' => 'El campo nombre no debe exceder 255 caracteres.', + + 'email.required' => 'El campo correo electrónico es obligatorio.', + 'email.string' => 'El campo correo electrónico debe ser una cadena de texto.', + 'email.email' => 'El campo correo electrónico debe ser una dirección de correo válida.', + 'email.max' => 'El campo correo electrónico no debe exceder 255 caracteres.', + 'email.unique' => 'El correo electrónico ya está registrado.', + + 'apellido.required' => 'El campo apellido es obligatorio.', + 'apellido.string' => 'El campo apellido debe ser una cadena de texto.', + 'apellido.max' => 'El campo apellido no debe exceder 255 caracteres.', + + 'tipos_id.required' => 'El campo tipo es obligatorio.', + 'tipos_id.exists' => 'El tipo seleccionado no es válido.', + + 'puesto_id.required' => 'El campo puesto es obligatorio.', + 'puesto_id.exists' => 'El puesto seleccionado no es válido.', + + 'departamento_id.required' => 'El campo departamento es obligatorio.', + 'departamento_id.exists' => 'El departamento seleccionado no es válido.', + + 'telefono.required' => 'El campo teléfono es obligatorio.', + 'telefono.string' => 'El campo teléfono debe ser una cadena de texto.', + 'telefono.max' => 'El campo teléfono no debe exceder 255 caracteres.', + + 'password.required' => 'El campo contraseña es obligatorio.', + 'password.string' => 'El campo contraseña debe ser una cadena de texto.', + 'password.min' => 'La contraseña debe tener al menos 8 caracteres.', + 'password.confirmed' => 'Las contraseñas no coinciden.', ]); + // Validación extra: si el usuario autenticado es de servicios generales, solo puede crear usuarios de tipo Usuario + if (auth()->user()->tipos_id == 4 && $request->tipos_id != 2) { + return redirect()->back()->withInput()->withErrors(['tipos_id' => 'Solo puedes crear usuarios de tipo Usuario.']); + } + // Si la validación pasa, crea el usuario $usuario = new User(); $usuario->name = $request->name; $usuario->email = $request->email; $usuario->apellido = $request->apellido; + $usuario->tipos_id = $request->tipos_id; $usuario->puesto_id = $request->puesto_id; $usuario->carrera = $request->carrera; $usuario->telefono = $request->telefono; $usuario->password = bcrypt($request->password); + // Ya no asignamos rol, solo usamos tipos_id $usuario->save(); return redirect()->route('usuarios')->with('success', 'Usuario creado exitosamente.'); @@ -90,7 +134,9 @@ class usuariosController extends Controller { $user = User::findOrFail($id); $puestos = Puesto::all(); - return view('usuariosCrearEditar',['usuario' => $user, 'puestos' => $puestos]); // Asegúrate de que la clave sea 'usuario' + $despartamentos = Despartamento::all(); + $tipos = Tipo::all(); + return view('usuariosCrearEditar',['usuario' => $user, 'puestos' => $puestos,'despartamentos'=> $despartamentos, 'tipos' => $tipos]); // Asegúrate de que la clave sea 'usuario' } // ... existing code ... @@ -100,15 +146,48 @@ class usuariosController extends Controller */ public function update(Request $request, $id) { - // Validación de datos + // Validación de datos (reglas y mensajes personalizados en español) $request->validate([ - 'name' => 'required|string|max:255', - 'email' => 'required|string|email|max:255', - 'apellido' => 'required|string|max:255', - //'puesto_id' => 'required|exists:puesto_id', - 'carrera' => 'required|string|max:255', - 'telefono' => 'required|string|max:255', - 'password' => 'nullable|string|min:8|confirmed', + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,'.$id], + 'apellido' => ['required', 'string', 'max:255'], + 'tipos_id' => ['required', 'exists:tipos,id'], + 'puesto_id' => ['required', 'exists:puestos,id'], + 'departamento_id' => ['required', 'exists:despartamentos,id'], + 'telefono' => ['required', 'string', 'max:255'], + 'password' => ['nullable', 'string', 'min:8', 'confirmed'], + ], [ + 'name.required' => 'El campo nombre es obligatorio.', + 'name.string' => 'El campo nombre debe ser una cadena de texto.', + 'name.max' => 'El campo nombre no debe exceder 255 caracteres.', + + 'email.required' => 'El campo correo electrónico es obligatorio.', + 'email.string' => 'El campo correo electrónico debe ser una cadena de texto.', + 'email.email' => 'El campo correo electrónico debe ser una dirección válida.', + 'email.max' => 'El campo correo electrónico no debe exceder 255 caracteres.', + 'email.unique' => 'El correo electrónico ya está registrado.', + + 'apellido.required' => 'El campo apellido es obligatorio.', + 'apellido.string' => 'El campo apellido debe ser una cadena de texto.', + 'apellido.max' => 'El campo apellido no debe exceder 255 caracteres.', + + 'tipos_id.required' => 'El campo tipo es obligatorio.', + 'tipos_id.exists' => 'El tipo seleccionado no es válido.', + + 'puesto_id.required' => 'El campo puesto es obligatorio.', + 'puesto_id.exists' => 'El puesto seleccionado no es válido.', + + 'departamento_id.required' => 'El campo departamento es obligatorio.', + 'departamento_id.exists' => 'El departamento seleccionado no es válido.', + + 'telefono.required' => 'El campo teléfono es obligatorio.', + 'telefono.string' => 'El campo teléfono debe ser una cadena de texto.', + 'telefono.max' => 'El campo teléfono no debe exceder 255 caracteres.', + + 'password.required' => 'El campo contraseña es obligatorio.', + 'password.string' => 'El campo contraseña debe ser una cadena de texto.', + 'password.min' => 'La contraseña debe tener al menos 8 caracteres.', + 'password.confirmed' => 'Las contraseñas no coinciden.', ]); // Actualizar usuario @@ -116,6 +195,7 @@ class usuariosController extends Controller $usuario->name = $request->name; $usuario->email = $request->email; $usuario->apellido = $request->apellido; + $usuario->tipos_id = $request->tipos_id; $usuario->puesto_id = $request->puesto_id; $usuario->carrera = $request->carrera; $usuario->telefono = $request->telefono; diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index bfe3685..d3bda25 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -60,9 +60,18 @@ class Kernel extends HttpKernel 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, + 'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class, 'signed' => \App\Http\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, + 'profesor' => \App\Http\Middleware\CheckProfesorRole::class, + 'admin' => \App\Http\Middleware\CheckAdminRole::class, + 'servicios' => \App\Http\Middleware\CheckServiciosRole::class, + 'adminOrServicios' => \App\Http\Middleware\AdminOrServiciosRole::class, + ]; + + protected $routeMiddleware = [ + // ... otros middlewares 'admin' => \App\Http\Middleware\AdminMiddleware::class, ]; } diff --git a/app/Http/Middleware/AdminMiddleware.php b/app/Http/Middleware/AdminMiddleware.php index b36ca95..909c8ae 100644 --- a/app/Http/Middleware/AdminMiddleware.php +++ b/app/Http/Middleware/AdminMiddleware.php @@ -4,16 +4,21 @@ namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; +use Symfony\Component\HttpFoundation\Response; class AdminMiddleware { - public function handle(Request $request, Closure $next) + /** + * Handle an incoming request. + * + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next + */ + public function handle(Request $request, Closure $next): Response { - if (Auth::check() && Auth::user()->email === 'monse@admin.com') { - return $next($request); + if (!auth()->check() || auth()->user()->tipos_id != 1) { + return redirect('/')->with('error', 'No tienes permisos para acceder a esta página.'); } - return redirect('/')->with('error', 'Acceso denegado. Solo los administradores pueden acceder a esta página.'); + return $next($request); } } diff --git a/app/Http/Middleware/AdminOrServiciosRole.php b/app/Http/Middleware/AdminOrServiciosRole.php new file mode 100644 index 0000000..87c506f --- /dev/null +++ b/app/Http/Middleware/AdminOrServiciosRole.php @@ -0,0 +1,23 @@ +check() || !in_array(auth()->user()->rol, ['admin', 'servicios'])) { + return redirect()->route('dashboard')->with('error', 'No tienes permisos para acceder a esta sección.'); + } + return $next($request); +} +} \ No newline at end of file diff --git a/app/Http/Middleware/CheckAdminRole.php b/app/Http/Middleware/CheckAdminRole.php new file mode 100644 index 0000000..fdc153f --- /dev/null +++ b/app/Http/Middleware/CheckAdminRole.php @@ -0,0 +1,20 @@ +check() || auth()->user()->tipos_id !== 1) { + return redirect()->route('dashboard') + ->with('error', 'No tienes permisos de administrador para acceder a esta sección.'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/CheckProfesorRole.php b/app/Http/Middleware/CheckProfesorRole.php new file mode 100644 index 0000000..27bb597 --- /dev/null +++ b/app/Http/Middleware/CheckProfesorRole.php @@ -0,0 +1,19 @@ +check() || auth()->user()->rol !== 'profesor') { + return redirect('/')->with('error', 'No tienes permiso para acceder a esta sección.'); + } + + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/CheckServiciosRole.php b/app/Http/Middleware/CheckServiciosRole.php new file mode 100644 index 0000000..ca349b9 --- /dev/null +++ b/app/Http/Middleware/CheckServiciosRole.php @@ -0,0 +1,19 @@ +check() || auth()->user()->tipos_id !== 4) { + return redirect('/')->with('error', 'No tienes permisos de servicios para acceder a esta sección.'); + } + + return $next($request); + } +} diff --git a/app/Models/Chofer.php b/app/Models/Chofer.php new file mode 100644 index 0000000..c185392 --- /dev/null +++ b/app/Models/Chofer.php @@ -0,0 +1,18 @@ +belongsTo(User::class); + } +} \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index fced612..a86ff38 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -22,6 +22,7 @@ class User extends Authenticatable 'name', 'email', 'apellido', + 'tipos_id', 'puesto_id', 'carrera', 'telefono', @@ -48,7 +49,7 @@ class User extends Authenticatable 'email_verified_at' => 'datetime', ]; - public function puesto():HasOne{ - return $this->hasOne(Puesto::class, 'id','puesto_id'); - } + public function puesto() { return $this->belongsTo(\App\Models\Puesto::class, 'puesto_id'); } + public function tipo() { return $this->belongsTo(\App\Models\Tipo::class, 'tipos_id'); } + public function departamento() { return $this->belongsTo(\App\Models\Despartamento::class, 'departamento_id'); } } diff --git a/app/Models/prestamo.php b/app/Models/prestamo.php index beab890..6cd1964 100644 --- a/app/Models/prestamo.php +++ b/app/Models/prestamo.php @@ -19,6 +19,18 @@ protected $fillable = [ 'domicilio', 'numero_personas', 'chofer', - + 'estado', + 'eliminado', + 'vehiculo_id' ]; + +public function vehiculo() +{ + return $this->belongsTo(\App\Models\tiposVeiculos::class, 'vehiculo_id'); +} + +public function choferAsignado() +{ + return $this->belongsTo(\App\Models\Chofer::class, 'chofer'); +} } diff --git a/app/Models/puesto.php b/app/Models/puesto.php index 70b90a4..57088c9 100644 --- a/app/Models/puesto.php +++ b/app/Models/puesto.php @@ -8,4 +8,5 @@ use Illuminate\Database\Eloquent\Model; class puesto extends Model { use HasFactory; + protected $fillable = ['nombre', 'eliminado']; } diff --git a/app/Models/tipo.php b/app/Models/tipo.php new file mode 100644 index 0000000..d115002 --- /dev/null +++ b/app/Models/tipo.php @@ -0,0 +1,13 @@ +registerPolicies(); +{ + $this->registerPolicies(); - // - } + Gate::define('gestionar-prestamos', function ($user) { + // Permitir solo a tipos_id 1 (Administrador) y 4 (Servicios Generales), agrega más si lo deseas + return in_array($user->tipos_id, [1, 4]); + }); +} } diff --git a/database/factories/TipoFactory.php b/database/factories/TipoFactory.php new file mode 100644 index 0000000..28b72c8 --- /dev/null +++ b/database/factories/TipoFactory.php @@ -0,0 +1,23 @@ + + */ +class TipoFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + // + ]; + } +} diff --git a/database/migrations/2013_02_20_022824_create_tipos_table.php b/database/migrations/2013_02_20_022824_create_tipos_table.php new file mode 100644 index 0000000..9c4f86a --- /dev/null +++ b/database/migrations/2013_02_20_022824_create_tipos_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('nombre'); + $table->timestamps(); + + }); + DB::table('tipos')->insert(['nombre'=> 'Administrador']); + DB::table('tipos')->insert(['nombre'=> 'Usuario']); + DB::table('tipos')->insert(['nombre'=> 'Jefe de Departamento']); + DB::table('tipos')->insert(['nombre'=> 'Servicios Generales']); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tipos'); + } +}; diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index 524739d..1fdb665 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -3,6 +3,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; return new class extends Migration { @@ -18,18 +19,73 @@ return new class extends Migration $table->timestamp('email_verified_at')->nullable(); $table->string('apellido')->nullable(); $table->unsignedBigInteger('puesto_id')->nullable(); - $table->string('carrera')->nullable(); + $table->unsignedBigInteger('departamento_id')->nullable(); + $table->unsignedBigInteger('tipos_id')->nullable(); $table->string('telefono')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); $table->foreign('puesto_id')->references('id')->on('puestos'); - + $table->foreign('departamento_id')->references('id')->on('despartamentos'); + $table->foreign('tipos_id')->references('id')->on('tipos'); }); DB::table('users')->insert([ - 'name'=> 'monse', - 'email'=> 'monse@admin.com', - 'password'=> bcrypt('tecmm2025') + [ + 'name' => 'usuario', + 'email' => 'usuario@usuario.com', + 'apellido' => 'usuario', + 'puesto_id' => 2, + 'departamento_id' => 2, + 'tipos_id' => 2, + 'telefono' => '33652147821', + 'password' => bcrypt('12345678'), + 'email_verified_at' => '2025-05-23 18:33:05', + 'remember_token' => null, + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'name' => 'monse', + 'email' => 'monse@monse.com', + 'apellido' => 'martinez', + 'puesto_id' => 1, + 'departamento_id' => 3, + 'tipos_id' => 1, + 'telefono' => null, + 'password' => bcrypt('12345678'), + 'email_verified_at' => '2025-05-23 18:33:05', + 'remember_token' => null, + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'name' => 'usuario_tipo3', + 'email' => 'tipo3@ejemplo.com', + 'apellido' => 'apellido3', + 'puesto_id' => 1, + 'departamento_id' => 1, + 'tipos_id' => 3, + 'telefono' => '3333333333', + 'password' => bcrypt('12345678'), + 'email_verified_at' => '2025-05-23 18:33:05', + 'remember_token' => null, + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'name' => 'jorge', + 'email' => 'jorge@jorge.com', + 'apellido' => 'jorge', + 'puesto_id' => 1, + 'departamento_id' => 1, + 'tipos_id' => 4, + 'telefono' => '4444444444', + 'password' => bcrypt('servicios123'), + 'email_verified_at' => '2025-05-23 18:33:05', + 'remember_token' => null, + 'created_at' => now(), + 'updated_at' => now(), + ], ]); } diff --git a/database/migrations/2024_03_19_create_user_dashboard_user.php b/database/migrations/2024_03_19_create_user_dashboard_user.php new file mode 100644 index 0000000..96358b7 --- /dev/null +++ b/database/migrations/2024_03_19_create_user_dashboard_user.php @@ -0,0 +1,31 @@ +where('email', 'usuarios@usuariosgmail.com')->first(); + + if (!$user) { + DB::table('users')->insert([ + 'name' => 'Usuario Dashboard', + 'email' => 'usuarios@usuariosgmail.com', + 'password' => Hash::make('usuario123'), + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + } + + public function down() + { + DB::table('users')->where('email', 'usuarios@usuariosgmail.com')->delete(); + } +}; diff --git a/database/migrations/2024_03_27_000000_create_solicitud_vehiculos_table.php b/database/migrations/2024_03_27_000000_create_solicitud_vehiculos_table.php new file mode 100644 index 0000000..dd48ec7 --- /dev/null +++ b/database/migrations/2024_03_27_000000_create_solicitud_vehiculos_table.php @@ -0,0 +1,28 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->date('fecha_solicitud'); + $table->time('hora_salida'); + $table->time('hora_regreso'); + $table->string('destino'); + $table->text('motivo'); + $table->enum('estado', ['pendiente', 'aprobada', 'rechazada'])->default('pendiente'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('solicitud_vehiculos'); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_03_27_174121_create_prestamos_table.php b/database/migrations/2025_03_27_174121_create_prestamos_table.php index 2ceb81f..3ae0b9b 100644 --- a/database/migrations/2025_03_27_174121_create_prestamos_table.php +++ b/database/migrations/2025_03_27_174121_create_prestamos_table.php @@ -21,6 +21,7 @@ return new class extends Migration $table->string('domicilio'); $table->integer('numero_personas'); $table->boolean('chofer')->default(false); // Opción de sí (true) o no (false) + $table->foreignId('vehiculo_id')->constrained('tipos_veiculos')->onDelete('cascade'); $table->timestamps(); }); } diff --git a/database/migrations/2025_03_28_182126_add_estado_to_prestamos_table.php b/database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php similarity index 55% rename from database/migrations/2025_03_28_182126_add_estado_to_prestamos_table.php rename to database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php index af9986e..1384d82 100644 --- a/database/migrations/2025_03_28_182126_add_estado_to_prestamos_table.php +++ b/database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php @@ -9,20 +9,22 @@ return new class extends Migration /** * Run the migrations. */ - public function up(): void + public function up() { Schema::table('prestamos', function (Blueprint $table) { - // + $table->string('estado')->default('pendiente'); }); } /** * Reverse the migrations. */ - public function down(): void - { - Schema::table('prestamos', function (Blueprint $table) { - // - }); + public function down() +{ + Schema::table('prestamos', function (Blueprint $table) { + if (Schema::hasColumn('prestamos', 'estado')) { + $table->dropColumn('estado'); + } + }); } }; diff --git a/database/migrations/2025_03_28_175646_add_estado_to_prestamos_table.php b/database/migrations/2025_04_01_192918_add_fecha_aceptacion_to_prestamos_table.php similarity index 81% rename from database/migrations/2025_03_28_175646_add_estado_to_prestamos_table.php rename to database/migrations/2025_04_01_192918_add_fecha_aceptacion_to_prestamos_table.php index af9986e..e671bde 100644 --- a/database/migrations/2025_03_28_175646_add_estado_to_prestamos_table.php +++ b/database/migrations/2025_04_01_192918_add_fecha_aceptacion_to_prestamos_table.php @@ -12,7 +12,7 @@ return new class extends Migration public function up(): void { Schema::table('prestamos', function (Blueprint $table) { - // + $table->timestamp('fecha_aceptacion')->nullable(); }); } @@ -22,7 +22,7 @@ return new class extends Migration public function down(): void { Schema::table('prestamos', function (Blueprint $table) { - // + $table->dropColumn('fecha_aceptacion'); }); } }; diff --git a/database/migrations/2025_05_22_205902_create_chofers_table.php b/database/migrations/2025_05_22_205902_create_chofers_table.php new file mode 100644 index 0000000..e81227b --- /dev/null +++ b/database/migrations/2025_05_22_205902_create_chofers_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('nombre'); + $table->string('tipo_licencia'); + $table->timestamps(); + }); +} + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('choferes'); + } +}; diff --git a/database/migrations/2025_05_22_212123_add_chofer_id_to_prestamos_table.php b/database/migrations/2025_05_22_212123_add_chofer_id_to_prestamos_table.php new file mode 100644 index 0000000..c7a6195 --- /dev/null +++ b/database/migrations/2025_05_22_212123_add_chofer_id_to_prestamos_table.php @@ -0,0 +1,25 @@ +foreignId('chofer_id')->nullable()->constrained('choferes')->onDelete('set null'); + }); +} +public function down() +{ + Schema::table('prestamos', function (Blueprint $table) { + $table->dropForeign(['chofer_id']); + $table->dropColumn('chofer_id'); + }); +} +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index a9f4519..7688ecf 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -18,5 +18,10 @@ class DatabaseSeeder extends Seeder // 'name' => 'Test User', // 'email' => 'test@example.com', // ]); + + $this->call([ + ProfesorSeeder::class, + ServiciosSeeder::class, + ]); } } diff --git a/database/seeders/ProfesorSeeder.php b/database/seeders/ProfesorSeeder.php new file mode 100644 index 0000000..e178ed1 --- /dev/null +++ b/database/seeders/ProfesorSeeder.php @@ -0,0 +1,22 @@ + 'Profesor', + 'email' => 'profesor@profesor.com', + 'password' => Hash::make('12345678'), + 'rol' => 'profesor', + 'apellido' => 'Ejemplo', + 'telefono' => '1234567890', + ]); + } +} \ No newline at end of file diff --git a/database/seeders/ServiciosSeeder.php b/database/seeders/ServiciosSeeder.php new file mode 100644 index 0000000..8860b87 --- /dev/null +++ b/database/seeders/ServiciosSeeder.php @@ -0,0 +1,26 @@ + 'jorge@jorge.com' ], + [ + 'name' => 'Jorge', + 'apellido' => 'Servicios', + 'telefono' => '1234567890', + 'password' => Hash::make('servicios123'), + 'tipos_id' => 4, + 'puesto_id' => 1, + 'departamento_id' => 1 + ] + ); + } +} diff --git a/ -i b/hollla.txt similarity index 100% rename from -i rename to hollla.txt diff --git a/public/css/user-dashboard.css b/public/css/user-dashboard.css new file mode 100644 index 0000000..7dbb1fa --- /dev/null +++ b/public/css/user-dashboard.css @@ -0,0 +1,85 @@ +body.user-dashboard-bg { + background: linear-gradient(120deg, #4158D0 0%, #5068c8 46%, #70e7ff 100%); + min-height: 100vh; +} + +.user-dashboard-header { + font-size: 2.2rem; + font-weight: 900; + color: #fff; + letter-spacing: 1px; + margin-top: 32px; + margin-left: 60px; + margin-bottom: 30px; + text-shadow: 0 2px 8px rgba(65,88,208,0.15); + text-align: left; +} + +.user-dashboard-card { + background: #fff; + border-radius: 24px; + box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15); + padding: 48px 32px; + max-width: 480px; + margin: 60px auto; + text-align: center; +} + +.user-dashboard-title { + font-size: 2.5rem; + font-weight: 800; + color: #2d3748; + margin-bottom: 18px; +} + +.user-dashboard-desc { + color: #6b7280; + font-size: 1.2rem; + margin-bottom: 32px; +} + +.user-dashboard-btn { + background: #4158D0; + color: #fff; + border: none; + border-radius: 8px; + padding: 14px 36px; + font-size: 1.1rem; + font-weight: 600; + box-shadow: 0 2px 8px rgba(65,88,208,0.15); + transition: background 0.2s; + cursor: pointer; +} +.user-dashboard-btn:hover { + background: #C850C0; + color: #fff; +} + +.user-dashboard-logout { + position: absolute; + top: 32px; + right: 60px; + z-index: 10; +} +.user-dashboard-logout-btn { + background: #e53e3e; + color: #fff; + border: none; + border-radius: 8px; + padding: 10px 22px; + font-size: 1rem; + font-weight: 600; + display: flex; + align-items: center; + gap: 8px; + box-shadow: 0 2px 8px rgba(229,62,62,0.15); + transition: background 0.2s; + cursor: pointer; +} +.user-dashboard-logout-btn:hover { + background: #c53030; + color: #fff; +} +.user-dashboard-logout-btn i { + font-size: 1.2rem; +} diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index ef7aad8..8f500d2 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -29,6 +29,14 @@ @endif + @if(session('error')) +
+
+ {{ session('error') }} +
+
+ @endif +
@csrf @@ -44,6 +52,12 @@ class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500" value="{{ old('email') }}" placeholder="tu@email.com"> + + @error('email') + + {{ $message }} + + @enderror @@ -58,6 +72,12 @@ + + @error('password') + + {{ $message }} + + @enderror diff --git a/resources/views/choferes.blade.php b/resources/views/choferes.blade.php new file mode 100644 index 0000000..43b0e83 --- /dev/null +++ b/resources/views/choferes.blade.php @@ -0,0 +1,95 @@ +@extends('layouts.dashboard') + +@section('content') +
+ @if(session('success')) + + @endif + @if(session('error')) + + @endif +
+
+

Gestión de Choferes

+ +
+
+ +
+ +
+ +
+
+ + @if(request('busqueda')) + Limpiar + @endif + +
+
+ + + + + + + + + + + @foreach($choferes as $chofer) + + + + + + + @endforeach + +
IDNombreTipo de LicenciaAcciones
{{ $chofer->id }} + + {{ $chofer->nombre }} + {{ $chofer->tipo_licencia }} +
+ +
+ @csrf + @method('DELETE') + +
+
+
+
+
+
+ +@endsection diff --git a/resources/views/choferesCrearEditar.blade.php b/resources/views/choferesCrearEditar.blade.php new file mode 100644 index 0000000..320a209 --- /dev/null +++ b/resources/views/choferesCrearEditar.blade.php @@ -0,0 +1,62 @@ +{{-- Start of Selection --}} +@extends('layouts.dashboard') + +@section('content') +
+
+
+
+
+

+ {{ isset($chofer) ? 'Editar Chofer' : 'Nuevo Chofer' }} +

+
+ +
+
+ @if($errors->any()) +
+
+ +
+
    + @foreach($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+
+
+ @endif +
+ @csrf + @if(isset($chofer)) + @method('PUT') + @endif +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ Cancelar + +
+
+
+
+
+
+
+@endsection +{{-- End of Selection --}} diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 6872ebf..7d72c75 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -1,6 +1,15 @@ @extends('layouts.dashboard') @section('content') +@if(!empty($notificaciones)) +
+ +
+@endif
@@ -10,8 +19,8 @@
-

25

-

↑ 12% desde el mes pasado

+

{{ $adminData['prestamosAceptados'] }}

+

Préstamos actualmente activos

@@ -22,32 +31,32 @@ -

150

-

↑ 5% desde el mes pasado

+

{{ $adminData['totalUsers'] }}

+

Total de usuarios en el sistema

- +
-

Préstamos Vencidos

+

Préstamos Pendientes

-

3

-

↓ 2% desde el mes pasado

+

{{ $adminData['prestamosPendientes'] }}

+

Préstamos por revisar

- +
-

Préstamos del Mes

+

Total Préstamos

-

42

-

↑ 8% desde el mes pasado

+

{{ $adminData['totalPrestamos'] }}

+

Total de préstamos registrados

@@ -66,34 +75,37 @@ - - -
-
- -
-
-
Juan Pérez
-
juan@example.com
-
-
- - -
Solicitó préstamo
- - -
Hace 2 horas
- - - - Aprobado - - - - + + + +
+ +
@endsection diff --git a/resources/views/exports/choferes-pdf.blade.php b/resources/views/exports/choferes-pdf.blade.php new file mode 100644 index 0000000..13a5825 --- /dev/null +++ b/resources/views/exports/choferes-pdf.blade.php @@ -0,0 +1,55 @@ + + + + Choferes + + + +
+

Reporte de Choferes

+

Fecha de generación: {{ date('d/m/Y H:i:s') }}

+
+ + + + + + + + + + + + @foreach($choferes as $chofer) + + + + + + + @endforeach + +
IDNombreTipo de LicenciaFecha de Creación
{{ $chofer->id }}{{ $chofer->nombre }}{{ $chofer->tipo_licencia }}{{ $chofer->created_at->format('d/m/Y') }}
+ + diff --git a/resources/views/exports/prestamo-individual-pdf.blade.php b/resources/views/exports/prestamo-individual-pdf.blade.php new file mode 100644 index 0000000..cd6b08f --- /dev/null +++ b/resources/views/exports/prestamo-individual-pdf.blade.php @@ -0,0 +1,66 @@ + + + + Reporte de Préstamo + + + +
+

REPORTE DE PRÉSTAMO

+

Fecha de generación: {{ now()->format('d/m/Y H:i') }}

+
+ + + + + + + + + + + + + + + + + + + + + +
SolicitanteDestinoFecha SalidaFecha LlegadaMotivoPersonasChoferEstado
{{ $prestamo->nombre_solicitante }}{{ $prestamo->destino }}{{ \Carbon\Carbon::parse($prestamo->fecha_hora_salida)->format('d/m/Y H:i') }}{{ \Carbon\Carbon::parse($prestamo->fecha_hora_llegada)->format('d/m/Y H:i') }}{{ $prestamo->motivo }}{{ $prestamo->numero_personas }}{{ $prestamo->choferAsignado ? $prestamo->choferAsignado->nombre : 'Sin chofer' }}{{ ucfirst($prestamo->estado) }}
+ + + + + +
_________________________
Solicitante
_________________________
Vo. Bo.
+ + diff --git a/resources/views/exports/prestamos-reporte-pdf.blade.php b/resources/views/exports/prestamos-reporte-pdf.blade.php new file mode 100644 index 0000000..d1b130b --- /dev/null +++ b/resources/views/exports/prestamos-reporte-pdf.blade.php @@ -0,0 +1,79 @@ + + + + Reporte General de Préstamos + + + +
+

REPORTE GENERAL DE PRÉSTAMOS

+

Fecha de generación: {{ now()->format('d/m/Y H:i') }}

+
+ + + + + + + + + + + + + + + + + + @foreach($prestamos as $i => $prestamo) + + + + + + + + + + + + + + @endforeach + +
#SolicitanteVehículoDestinoFecha SalidaFecha LlegadaMotivoDomicilioPersonasChoferEstado
{{ $i + 1 }}{{ $prestamo->nombre_solicitante }}{{ $prestamo->vehiculo->nombre ?? '-' }}{{ $prestamo->destino }}{{ \Carbon\Carbon::parse($prestamo->fecha_hora_salida)->format('d/m/Y H:i') }}{{ \Carbon\Carbon::parse($prestamo->fecha_hora_llegada)->format('d/m/Y H:i') }}{{ $prestamo->motivo }}{{ $prestamo->domicilio }}{{ $prestamo->numero_personas }}{{ $prestamo->choferAsignado ? $prestamo->choferAsignado->nombre : 'Sin chofer' }}{{ ucfirst($prestamo->estado) }}
+ + + + + +
_________________________
Elaboró
_________________________
Vo. Bo.
+ + diff --git a/resources/views/exports/puestos.blade.php b/resources/views/exports/puestos.blade.php new file mode 100644 index 0000000..23b90f6 --- /dev/null +++ b/resources/views/exports/puestos.blade.php @@ -0,0 +1,53 @@ + + + + Reporte de Puestos + + + +
+

Reporte de Puestos

+

Fecha de generación: {{ date('d/m/Y H:i:s') }}

+
+ + + + + + + + + + + @foreach($puestos as $index => $puesto) + + + + + + @endforeach + +
#Nombre del Puesto
{{ $index + 1 }}{{ $puesto->nombre }}
+ + diff --git a/resources/views/exports/tipos_vehiculos_pdf.blade.php b/resources/views/exports/tipos_vehiculos_pdf.blade.php index 9bed25e..93e2966 100644 --- a/resources/views/exports/tipos_vehiculos_pdf.blade.php +++ b/resources/views/exports/tipos_vehiculos_pdf.blade.php @@ -72,4 +72,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/resources/views/exports/usuarios-pdf.blade.php b/resources/views/exports/usuarios-pdf.blade.php index 29b1550..879f478 100644 --- a/resources/views/exports/usuarios-pdf.blade.php +++ b/resources/views/exports/usuarios-pdf.blade.php @@ -4,45 +4,60 @@ Lista de Usuarios +

Lista de Usuarios

+

Fecha de generación: {{ date('d/m/Y H:i:s') }}

+
- + - + + - @foreach($usuarios as $usuario) + @foreach($usuarios as $index => $usuario) - + - - + + + @endforeach
IDNo. Nombre Email Apellido PuestoCarreraTipoDepartamento Teléfono
{{ $usuario->id }}{{ $index + 1 }} {{ $usuario->name }} {{ $usuario->email }} {{ $usuario->apellido }}{{ $usuario->puesto }}{{ $usuario->carrera }}{{ $usuario->puesto->nombre ?? '' }}{{ $usuario->tipo->nombre ?? '' }}{{ $usuario->departamento->departamento ?? '' }} {{ $usuario->telefono }}
- \ No newline at end of file + diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 2e91f86..a143fa3 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -15,11 +15,12 @@ - +
+ @if (!request()->is('user-dashboard') && !request()->is('user-dashboard/cuestionario') && !request()->is('user-dashboard/prestamos-aceptados'))
- + @endif
@yield('content')
diff --git a/resources/views/layouts/dashboard.blade.php b/resources/views/layouts/dashboard.blade.php index 6269572..cd131de 100644 --- a/resources/views/layouts/dashboard.blade.php +++ b/resources/views/layouts/dashboard.blade.php @@ -73,29 +73,31 @@ class="pl-4 mt-2 space-y-1 text-sm">
  • - + Nuevo Préstamo
  • -
  • +
  • - - - Préstamos Rechazados + + + Préstamos pendientes/aceptados
  • - - - Préstamos Aceptados + + + Préstamos Rechazados
  • +
  • @@ -150,6 +152,22 @@ Marca
  • + +
  • + + + Puestos + +
  • + + +
  • + + + Departamentos + +
  • +
  • @@ -161,9 +179,9 @@
  • - + - Tipos de Licencia + Choferes
  • @@ -181,17 +199,7 @@ Tipo de Gasolina - -
  • - +