@php $configData = Helper::appClasses(); @endphp @extends('layouts/layoutMaster') @section('title', 'Detalle de usuario') @section('vendor-style') @vite([ 'resources/assets/vendor/libs/datatables-bs5/datatables.bootstrap5.scss', 'resources/assets/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.scss', 'resources/assets/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.scss', 'resources/assets/vendor/libs/animate-css/animate.scss', 'resources/assets/vendor/libs/sweetalert2/sweetalert2.scss', 'resources/assets/vendor/libs/select2/select2.scss', 'resources/assets/vendor/libs/@form-validation/form-validation.scss' ]) @endsection @section('page-style') @vite('resources/assets/vendor/scss/pages/page-user-view.scss') @endsection @section('vendor-script') @vite([ 'resources/assets/vendor/libs/moment/moment.js', 'resources/assets/vendor/libs/datatables-bs5/datatables-bootstrap5.js', 'resources/assets/vendor/libs/sweetalert2/sweetalert2.js', 'resources/assets/vendor/libs/cleave-zen/cleave-zen.js', 'resources/assets/vendor/libs/select2/select2.js', 'resources/assets/vendor/libs/@form-validation/popular.js', 'resources/assets/vendor/libs/@form-validation/bootstrap5.js', 'resources/assets/vendor/libs/@form-validation/auto-focus.js' ]) @endsection @section('page-script') @vite(['resources/assets/js/modal-edit-user.js', 'resources/assets/js/app-user-view.js', 'resources/assets/js/app-user-view-account.js']) @endsection
Detalle forecast
Selecciona un día para ver el detalle.
Franja Pedidos Demanda total Consumo propio Consumo otras flotas Restante
No hay forecast disponible para este día.
@section('content') @php $from = request()->query('from'); $prev = url()->previous(); $backUrl = $from === 'riders' || \Illuminate\Support\Str::contains($prev, '/admin/riders') ? route('admin.riders') : route('admin.users.index'); $vehicleHistory = collect($vehicleAssignments ?? []); $activeVehicleAssignment = $vehicleHistory->firstWhere('returned_at', null); $primaryRole = optional($user->roles->first()); $roleName = $primaryRole->name ?? 'Sin asignar'; $roleSlug = $primaryRole->slug ?? ''; $isAdmin = method_exists($user, 'isAdmin') ? $user->isAdmin() : false; $isRider = str_contains(strtolower($roleSlug), 'rider') || str_contains(strtolower($roleSlug), 'repart') || str_contains(strtolower($roleSlug), 'courier'); $roleIcon = $isAdmin ? 'ti tabler-settings-cog' : ($isRider ? 'ti tabler-bike' : 'ti tabler-user-circle'); $badgeTone = $isAdmin ? 'bg-label-danger' : ($isRider ? 'bg-label-success' : 'bg-label-info'); $statusBadgeClass = $user->active ? 'bg-label-success' : 'bg-label-secondary'; $statusLabel = $user->active ? 'Activo' : 'Inactivo'; $manualHoursWeek = number_format((float)($scheduleTotals['manual_hours_week'] ?? 0), 2, ',', '.'); $manualHoursTotal = number_format((float)($scheduleTotals['manual_hours_total'] ?? 0), 2, ',', '.'); $forecastHoursWeek = number_format((float)($scheduleTotals['forecast_hours_week'] ?? 0), 2, ',', '.'); $forecastHoursTotal = number_format((float)($scheduleTotals['forecast_hours_total'] ?? 0), 2, ',', '.'); $avatarColorPalette = [ 'bg-label-primary', 'bg-label-success', 'bg-label-info', 'bg-label-warning', 'bg-label-danger', 'bg-label-secondary', 'bg-label-dark', ]; $nameParts = preg_split('/\s+/', trim($user->name ?? ''), -1, PREG_SPLIT_NO_EMPTY); $avatarInitials = collect($nameParts) ->map(fn ($part) => mb_strtoupper(mb_substr($part, 0, 1))) ->filter() ->take(2) ->implode(''); if ($avatarInitials === '') { $identifier = $user->email ?? $user->dni ?? 'Rider'; $avatarInitials = strtoupper(mb_substr($identifier, 0, 2)); } $avatarSeed = $user->id ?? crc32($user->email ?? $user->name ?? 'seed'); $avatarColor = $avatarColorPalette[$avatarSeed % count($avatarColorPalette)] ?? $avatarColorPalette[0]; $vehicleSummary = 'Sin vehículo asignado'; if ($activeVehicleAssignment) { $vehicleParts = []; $vehicleParts[] = optional($activeVehicleAssignment->vehicle)->name ?? '—'; if (($activeVehicleAssignment->vehicle_source ?? null) === 'company') { $vehicleParts[] = 'Empresa' . (optional($activeVehicleAssignment->company)->name ? ': ' . optional($activeVehicleAssignment->company)->name : ''); } elseif (($activeVehicleAssignment->vehicle_source ?? null) === 'personal') { $vehicleParts[] = 'Personal'; } if ($activeVehicleAssignment->vehicle_monthly_cost) { $vehicleParts[] = number_format((float) $activeVehicleAssignment->vehicle_monthly_cost, 2, ',', '.') . ' € / mes'; } if ($activeVehicleAssignment->assigned_at) { $vehicleParts[] = 'Desde ' . $activeVehicleAssignment->assigned_at->format('d/m/Y'); } $vehicleSummary = implode(' · ', array_filter($vehicleParts)); } $credentialsCollection = $glovoCredentials instanceof \Illuminate\Support\Collection ? $glovoCredentials : collect($glovoCredentials); $riderIds = $credentialsCollection->pluck('rider_id')->filter()->unique()->values(); $primaryRiderId = $riderIds->first(); $additionalRiderIds = $riderIds->skip(1); $scheduleBoardWeekStart = \Illuminate\Support\Carbon::now()->startOfWeek(\Illuminate\Support\Carbon::MONDAY); $scheduleBoardDays = collect(range(0, 6))->map(fn ($offset) => $scheduleBoardWeekStart->copy()->addDays($offset)); $scheduleBoardSlots = collect(range(0, 47))->map(function ($slot) { $minutes = $slot * 30; $hour = intdiv($minutes, 60); $minute = $minutes % 60; return sprintf('%02d:%02d', $hour, $minute); }); $scheduleBoardWeekEnd = $scheduleBoardWeekStart->copy()->addDays(6); $scheduleBoardWeekLabel = $scheduleBoardWeekStart->translatedFormat('d \de F') . ' – ' . $scheduleBoardWeekEnd->translatedFormat('d \de F Y'); $manualSchedule = $manualScheduleState ?? [ 'available' => true, 'enabled' => false, 'raw_flag' => false, 'week_start' => $scheduleBoardWeekStart->toDateString(), 'week_label' => $scheduleBoardWeekLabel, 'week' => null, 'manual_week_label' => null, 'eligible' => true, 'has_forecast' => false, 'active_other_week' => false, ]; $manualHoursValue = round((float)($scheduleTotals['manual_hours_total'] ?? 0), 2); $forecastHoursValue = round((float)($scheduleTotals['forecast_hours_total'] ?? 0), 2); $totalHoursValue = max($manualHoursValue + $forecastHoursValue, 0); $manualShare = $totalHoursValue > 0 ? round(($manualHoursValue / $totalHoursValue) * 100) : 0; $forecastShare = $totalHoursValue > 0 ? round(($forecastHoursValue / $totalHoursValue) * 100) : 0; $totalHoursPretty = number_format($totalHoursValue, 2, ',', '.'); $manualHoursPretty = number_format($manualHoursValue, 2, ',', '.'); $forecastHoursPretty = number_format($forecastHoursValue, 2, ',', '.'); $lastShift = $scheduleHistory->first(); $lastShiftDateLabel = $lastShift && $lastShift->slot_date ? \Illuminate\Support\Carbon::parse($lastShift->slot_date)->translatedFormat('d M Y') : 'Sin registros'; $lastShiftTimeLabel = $lastShift && $lastShift->slot_time ? substr((string) $lastShift->slot_time, 0, 5) : '—'; $lastShiftSource = $lastShift ? ($lastShift->source === 'manual' ? 'Manual' : ucfirst($lastShift->source ?? 'Forecast')) : null; $lastShiftSourceBadge = 'bg-label-secondary'; if ($lastShiftSource === 'Manual') { $lastShiftSourceBadge = 'bg-label-success'; } elseif ($lastShiftSource === 'Forecast') { $lastShiftSourceBadge = 'bg-label-info'; } $lastShiftAssignedBy = $lastShift && ($lastShift->relationLoaded('assignedBy') || isset($lastShift->assignedBy)) ? (optional($lastShift->assignedBy)->name ?? '—') : '—'; $companiesCount = $user->companies->count(); $citiesCount = $user->cities->count(); $zonesCount = $user->zones->count(); $accountAgeLabel = optional($user->created_at)?->diffForHumans() ?? '—'; $manualScheduleStatusLabel = 'No disponible'; $manualScheduleStatusBadge = 'bg-label-secondary'; if ($manualSchedule['available']) { if ($manualSchedule['enabled']) { $manualScheduleStatusLabel = 'Activo esta semana'; $manualScheduleStatusBadge = 'bg-label-success'; } elseif (!empty($manualSchedule['raw_flag'])) { $manualScheduleStatusLabel = 'Programado'; $manualScheduleStatusBadge = 'bg-label-warning'; } else { $manualScheduleStatusLabel = 'Desactivado'; $manualScheduleStatusBadge = 'bg-label-secondary'; } } $manualScheduleWeekLabel = $manualSchedule['manual_week_label'] ?? ($manualSchedule['week_label'] ?? null); $vehicleNameLabel = optional(optional($activeVehicleAssignment)->vehicle)->name ?? 'Sin vehículo asignado'; $vehicleStatusBadge = $activeVehicleAssignment ? 'bg-label-success' : 'bg-label-secondary'; $vehicleLastChange = $vehicleHistory->first(); if ($vehicleLastChange) { $vehicleChangeDate = optional($vehicleLastChange->assigned_at) ?: optional($vehicleLastChange->created_at); $vehicleLastChangeLabel = $vehicleChangeDate ? $vehicleChangeDate->format('d/m/Y') : '—'; } else { $vehicleLastChangeLabel = '—'; } $primaryCompanyName = optional($user->companies->first())->name ?? 'Sin empresa principal'; $primaryCityName = optional($user->cities->first())->name ?? null; $userPhone = $user->phone ?? trim(($user->phone_prefix ?? '') . ' ' . ($user->phone_number ?? '')); $userPhone = $userPhone !== '' ? $userPhone : null; @endphp
Volver
{{ $avatarInitials }}

{{ $user->name }}

{{ $roleName }} {{ $statusLabel }}
  • {{ $user->email ?: 'Sin correo' }}
  • {{ $user->dni ?: 'Sin documento' }}
  • {{ $accountAgeLabel }}
  • @if($user->sesame_employee_id)
  • Sesame {{ $user->sesame_employee_id }}
  • @endif @if($primaryCityName)
  • {{ $primaryCityName }}
  • @endif
@if($primaryRiderId) Rider ID {{ $primaryRiderId }} @endif {{ $primaryCompanyName }} {{ $manualHoursPretty }}h manual / {{ $forecastHoursPretty }}h forecast {{ $vehicleNameLabel }}
Editar perfil {{ $user->active ? 'Suspender' : 'Activar' }} @if($userPhone) Llamar @endif @if($user->email) Enviar email @endif @if(auth()->check() && method_exists(auth()->user(), 'isAdmin') && auth()->user()->isAdmin() && auth()->id() !== $user->id)
@csrf
@endif
Horas totales
{{ $totalHoursPretty }} h
Manual {{ $manualShare }}% · Forecast {{ $forecastShare }}%
Último turno
{{ $lastShiftDateLabel }}
Inicio {{ $lastShiftTimeLabel }} {{ $lastShiftSource ?? '—' }}
Asignado por {{ $lastShiftAssignedBy }}
Cobertura activa
{{ $companiesCount + $citiesCount + $zonesCount }}
  • {{ $companiesCount }} empresas
  • {{ $citiesCount }} ciudades
  • {{ $zonesCount }} zonas
Operativa
{{ $vehicleNameLabel }}
{{ $activeVehicleAssignment ? 'Asignado' : 'Sin asignar' }} Actualizado {{ $vehicleLastChangeLabel }}
Horario manual: {{ $manualScheduleStatusLabel }}
Información general
Datos clave y estado operativo
Correo {{ $user->email ?: 'Sin información' }}
@if($userPhone)
Teléfono {{ $userPhone }}
@endif
DNI / NIE {{ $user->dni ?: 'Sin información' }}
Rider ID Glovo {{ $primaryRiderId ?? 'Sin rider ID' }} @if($additionalRiderIds->isNotEmpty())
Otros: {{ $additionalRiderIds->implode(', ') }}
@endif
Estado {{ $statusLabel }}
Rol principal {{ $roleName }}
Costo por pedido {{ $user->cost_per_order !== null ? number_format((float) $user->cost_per_order, 2, ',', '.') . ' €' : '—' }}
Costo por hora {{ $user->cost_per_hour !== null ? number_format((float) $user->cost_per_hour, 2, ',', '.') . ' €' : '—' }}
Vehículo actual {{ $vehicleSummary }}
Registrado el {{ optional($user->created_at)->format('d/m/Y H:i') ?? '—' }}
Cobertura operativa
Empresas, ciudades y zonas asignadas
Empresas @forelse($user->companies as $company) {{ $company->name }} @empty Sin asignar @endforelse
Ciudades @forelse($user->cities as $city) {{ $city->name }} @empty Sin asignar @endforelse
Zonas @forelse($user->zones as $zone) {{ $zone->name }} @empty Sin asignar @endforelse
Contrato de horas
Gestiona las horas semanales pactadas
Contrato vigente
Se actualizará al cargar el historial.
El equipo administrativo verá estas notas en el historial.
Se marcará como finalizado el contrato anterior un día antes de la nueva vigencia.
Historial
Sin registros
Planificación reciente
Se muestran los últimos 300 turnos registrados
{{ $manualHoursWeek }} h manual (sem.) {{ $manualHoursTotal }} h manual (hist.) {{ $forecastHoursWeek }} h forecast (sem.) {{ $forecastHoursTotal }} h forecast (hist.)
Planificador
Gestiona la disponibilidad del rider por día, semana o mes.
{{ $scheduleBoardWeekLabel }}
@if ($manualSchedule['available'] && ($manualSchedule['eligible'] || $manualSchedule['enabled'] || $manualSchedule['active_other_week'] || $manualSchedule['locked'])) @endif @if ($manualSchedule['available']) @endif @if (!$manualSchedule['available']) Configura la base de datos para habilitar modo manual @elseif($manualSchedule['locked']) Horario bloqueado para el rider @elseif ($manualSchedule['enabled']) Modo manual activo @elseif($manualSchedule['active_other_week']) Manual programado para {{ $manualSchedule['manual_week_label'] ?? 'otra semana' }} @elseif(!$manualSchedule['eligible']) Forecast publicado para esta semana @else Manual deshabilitado @endif @if (!$manualSchedule['available']) Ejecuta las migraciones pendientes para usar la planificación manual. @endif
{{ $manualSchedule['week_label'] }}
BOOK UNBOOK Forecast Forecast (este rider)
Hora
@foreach($scheduleBoardDays as $day) @php $dateKey = $day->format('Y-m-d'); @endphp
{{ $day->translatedFormat('l d') }} {{ $day->translatedFormat('F Y') }}
@endforeach
@foreach($scheduleBoardSlots as $slotLabel)
{{ $slotLabel }}
@foreach($scheduleBoardDays as $day) @php $dateKey = $day->format('Y-m-d'); @endphp
@endforeach
@endforeach
Selecciona un día
0 h
@foreach($scheduleBoardSlots as $slotLabel)
{{ $slotLabel }}
@endforeach
Mes actual
Resumen de horas y estado
@if($scheduleHistory->isEmpty())
Este rider aún no tiene turnos registrados. Usa el planificador para crear su primera planificación.
@endif
--
Pedidos
--
Horas
--
Eficiencia
--
CDT Promedio
--
% Ineligible
--
Cash Total
--
Asignación vehículo
Periodo Día Pedidos Horas No Show (tiempo) Eficiencia Cancelados Reasign. No Show Ineligible CDT Asignación vehículo (€) Cash (€)
Cargando...
Página 1 de 1
Historial de asignaciones
Credenciales Glovo y otros accesos
Rider ID Asignada Hasta Por Motivo Estado
Selecciona "Actualizar" para obtener los registros.
Seguimiento mensual
@php $calendarWeeklyTarget = (float) ($user->weekly_contract_hours ?? 0); if ($calendarWeeklyTarget <= 0) { $calendarWeeklyTarget = 40.0; } @endphp
Selecciona un mes para visualizar el detalle.

Saldo disponible
EUR
Último movimiento:
Sin registros
Registrar movimiento
Saldo seguro · Validación automática
Historial del monedero
Mostrando hasta 20 movimientos recientes.
Sin actualizar
Fecha Tipo Importe Saldo tras movimiento Descripción Autor
Carga inicial pendiente…
Vehículo activo
Estado operativo del rider

Asigna un vehículo para ver aquí los detalles del actual.

Asignar nuevo vehículo
Registra el vehículo operativo y sus condiciones.
Solo aplica si el vehículo es de empresa.
Historial de vehículos
Seguimiento de asignaciones y devoluciones
Asignación activa
Aún no se registran asignaciones de vehículos para este usuario.
@include('_partials/_modals/modal-edit-user') @include('_partials/_modals/modal-upgrade-plan') @php $glovoCredentialsPayload = ($glovoCredentials ?? collect())->map(function ($cred) { return [ 'id' => $cred->id, 'courier_id' => $cred->courier_id, 'city_code' => $cred->city_code, 'rider_id' => $cred->rider_id, 'login_email' => $cred->login_email, 'status' => $cred->status, 'provided_at' => optional($cred->provided_at)->format('Y-m-d H:i:s'), ]; })->values(); $vehicleAssignmentsPayload = $vehicleHistory->map(function ($assignment) { return [ 'id' => $assignment->id, 'vehicle_id' => $assignment->vehicle_id, 'vehicle_name' => optional($assignment->vehicle)->name, 'vehicle_code' => optional($assignment->vehicle)->code, 'vehicle_source' => $assignment->vehicle_source, 'vehicle_company_id' => $assignment->vehicle_company_id, 'vehicle_company_name' => optional($assignment->company)->name, 'vehicle_monthly_cost' => $assignment->vehicle_monthly_cost !== null ? (float) $assignment->vehicle_monthly_cost : null, 'assigned_at' => optional($assignment->assigned_at)->toDateString(), 'returned_at' => optional($assignment->returned_at)->toDateString(), 'vehicle_notes' => $assignment->vehicle_notes, 'created_by' => optional($assignment->creator)->name, ]; })->values(); $vehicleOptionsPayload = ($glovoVehicles ?? collect())->map(function ($vehicle) { return [ 'id' => $vehicle->id, 'name' => $vehicle->name, 'code' => $vehicle->code, ]; })->values(); $vehicleCompaniesPayload = ($vehicleCompanies ?? collect())->map(function ($company) { return [ 'id' => $company->id, 'name' => $company->name, ]; })->values(); @endphp @endsection @push('scripts') @endpush