authorizeAbility($request, 'security.view'); $organization = $this->organization($request); $owner = $this->ownerRef($request); $occupancy = Visit::owned($owner) ->where('organization_id', $organization->id) ->currentlyInside() ->with(['visitor', 'host']); $this->scopeToBranch($request, $occupancy); $occupancy = $occupancy->orderBy('checked_in_at')->get(); $staffOnSite = $this->staffOccupancy($request, $owner, $organization); $expiredBadges = $occupancy->filter(fn (Visit $v) => $v->isBadgeExpired()); return view('frontdesk.security.index', [ 'occupancy' => $occupancy, 'staffOnSite' => $staffOnSite, 'expiredBadges' => $expiredBadges, 'organization' => $organization, 'canCheckout' => app(\App\Services\Frontdesk\FrontdeskPermissions::class) ->can($this->member($request), 'security.checkout'), ]); } public function evacuation(Request $request): View { $this->authorizeAbility($request, 'security.view'); $organization = $this->organization($request); $owner = $this->ownerRef($request); $occupancy = Visit::owned($owner) ->where('organization_id', $organization->id) ->currentlyInside() ->with(['visitor', 'host', 'branch']); $this->scopeToBranch($request, $occupancy); $occupancy = $occupancy->orderBy('checked_in_at')->get(); $staffOnSite = $this->staffOccupancy($request, $owner, $organization, withBranch: true); return view('frontdesk.security.evacuation', compact('occupancy', 'staffOnSite', 'organization')); } public function evacuationExport(Request $request): StreamedResponse { $this->authorizeAbility($request, 'security.view'); $organization = $this->organization($request); $owner = $this->ownerRef($request); $occupancy = Visit::owned($owner) ->where('organization_id', $organization->id) ->currentlyInside() ->with(['visitor', 'host', 'branch']); $this->scopeToBranch($request, $occupancy); $occupancy = $occupancy->orderBy('checked_in_at')->get(); $staffOnSite = $this->staffOccupancy($request, $owner, $organization, withBranch: true); $filename = 'evacuation-'.now()->format('Y-m-d-His').'.csv'; return response()->streamDownload(function () use ($occupancy, $staffOnSite) { $handle = fopen('php://output', 'w'); fputcsv($handle, ['Type', 'Name', 'Detail', 'Branch', 'Since', 'Phone', 'Status']); foreach ($occupancy as $visit) { fputcsv($handle, [ 'Visitor', $visit->visitor->full_name, ucfirst(str_replace('_', ' ', $visit->visitor_type)).($visit->host ? ' · Host: '.$visit->host->name : ''), $visit->branch?->name ?? '—', $visit->checked_in_at?->format('Y-m-d g:i A') ?? '—', $visit->visitor->phone ?? '—', 'On site', ]); } foreach ($staffOnSite as $presence) { fputcsv($handle, [ 'Staff', $presence->employee->full_name, $presence->employee->department ?? '—', $presence->branch?->name ?? $presence->employee->branch?->name ?? '—', $presence->signed_in_at?->format('Y-m-d g:i A') ?? '—', $presence->employee->phone ?? '—', config('frontdesk.employee_presence_statuses.'.$presence->status, $presence->status) .($presence->destination ? ' · '.$presence->destination : ''), ]); } fclose($handle); }, $filename, ['Content-Type' => 'text/csv']); } public function evacuationBadges(Request $request, \App\Services\Frontdesk\BadgeRenderService $badges): View { $this->authorizeAbility($request, 'security.view'); $organization = $this->organization($request); $owner = $this->ownerRef($request); $visits = Visit::owned($owner) ->where('organization_id', $organization->id) ->currentlyInside() ->with(['visitor', 'host', 'organization']); $this->scopeToBranch($request, $visits); $visits = $visits->orderBy('checked_in_at')->get(); $rendered = $visits->map(fn (Visit $visit) => $badges->renderHtml($visit)); return view('frontdesk.security.evacuation-badges', compact('visits', 'rendered', 'organization')); } public function checkOut(Request $request, Visit $visit, VisitCheckOutService $checkOut): RedirectResponse { $this->authorizeAbility($request, 'security.checkout'); $this->authorizeOwner($request, $visit); $checkOut->checkOut($visit, $this->ownerRef($request)); return back()->with('success', 'Visitor checked out.'); } public function verifyForm(Request $request): View { $this->authorizeAbility($request, 'security.verify'); return view('frontdesk.security.verify', [ 'organization' => $this->organization($request), ]); } public function verify(Request $request): View { $this->authorizeAbility($request, 'security.verify'); $organization = $this->organization($request); $owner = $this->ownerRef($request); $validated = $request->validate([ 'lookup' => ['required', 'string', 'max:64'], ]); $lookup = trim($validated['lookup']); $visit = Visit::owned($owner) ->where('organization_id', $organization->id) ->where(function ($q) use ($lookup) { $q->where('badge_code', strtoupper($lookup)) ->orWhere('qr_token', $lookup); }) ->with(['visitor', 'host', 'branch']) ->latest('checked_in_at') ->first(); return view('frontdesk.security.verify', [ 'organization' => $organization, 'lookup' => $lookup, 'visit' => $visit, ]); } protected function staffOccupancy(Request $request, string $owner, $organization, bool $withBranch = false) { $query = EmployeePresence::query() ->whereIn('status', [EmployeePresence::STATUS_ON_SITE, EmployeePresence::STATUS_STEPPED_OUT]) ->whereHas('employee', function ($q) use ($owner, $organization, $request) { $q->owned($owner)->where('organization_id', $organization->id)->where('active', true); $this->scopeToBranch($request, $q, 'branch_id'); }) ->with(['employee']); if ($withBranch) { $query->with(['branch', 'employee.branch']); } return $query->orderBy('employee_id')->get(); } }