Visitor management app with SSO, kiosk, badges, reports, and Gitea CI deploy to frontdesk.ladill.com. Co-authored-by: Cursor <cursoragent@cursor.com>
146 lines
5.2 KiB
PHP
146 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Api\Concerns\ScopesToOwner;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Organization;
|
|
use App\Models\Visit;
|
|
use App\Services\Frontdesk\VisitCheckInService;
|
|
use App\Services\Frontdesk\VisitCheckOutService;
|
|
use App\Services\Frontdesk\VisitLifecycleService;
|
|
use App\Services\Frontdesk\VisitScheduleService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
|
|
class VisitController extends Controller
|
|
{
|
|
use ScopesToOwner;
|
|
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$owner = $this->ownerRef($request);
|
|
|
|
$visits = Visit::owned($owner)
|
|
->with(['visitor', 'host'])
|
|
->when($request->status, fn ($q, $s) => $q->where('status', $s))
|
|
->latest()
|
|
->paginate(min((int) $request->query('per_page', 25), 100));
|
|
|
|
return response()->json($visits);
|
|
}
|
|
|
|
public function store(Request $request, VisitCheckInService $checkIn, VisitScheduleService $scheduler): JsonResponse
|
|
{
|
|
$owner = $this->ownerRef($request);
|
|
$organization = Organization::owned($owner)->findOrFail($request->integer('organization_id'));
|
|
$source = (string) $request->attributes->get('service_caller', 'api');
|
|
|
|
if ($request->filled('external_ref')) {
|
|
$existing = Visit::owned($owner)
|
|
->where('organization_id', $organization->id)
|
|
->where('external_ref', $request->string('external_ref'))
|
|
->where('source', $source)
|
|
->with(['visitor', 'host'])
|
|
->first();
|
|
|
|
if ($existing) {
|
|
return response()->json($existing);
|
|
}
|
|
}
|
|
|
|
if ($request->boolean('schedule')) {
|
|
$validated = $request->validate([
|
|
'organization_id' => ['required', 'integer'],
|
|
'external_ref' => ['nullable', 'string', 'max:128'],
|
|
'visitor_id' => ['nullable', 'integer'],
|
|
'full_name' => ['required_without:visitor_id', 'string', 'max:255'],
|
|
'company' => ['nullable', 'string'],
|
|
'phone' => ['nullable', 'string'],
|
|
'email' => ['nullable', 'email'],
|
|
'host_id' => ['nullable', 'integer'],
|
|
'branch_id' => ['nullable', 'integer'],
|
|
'visitor_type' => ['required', 'string'],
|
|
'purpose' => ['nullable', 'string'],
|
|
'scheduled_at' => ['required', 'date'],
|
|
'notes' => ['nullable', 'string'],
|
|
'integration_metadata' => ['nullable', 'array'],
|
|
]);
|
|
|
|
$visit = $scheduler->schedule($owner, $organization, [
|
|
...$validated,
|
|
'source' => $source,
|
|
]);
|
|
|
|
return response()->json($visit->load(['visitor', 'host']), 201);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'organization_id' => ['required', 'integer'],
|
|
'external_ref' => ['nullable', 'string', 'max:128'],
|
|
'full_name' => ['required', 'string', 'max:255'],
|
|
'company' => ['nullable', 'string'],
|
|
'phone' => ['nullable', 'string'],
|
|
'email' => ['nullable', 'email'],
|
|
'host_id' => ['nullable', 'integer'],
|
|
'visitor_type' => ['required', 'string'],
|
|
'purpose' => ['nullable', 'string'],
|
|
'integration_metadata' => ['nullable', 'array'],
|
|
'policies_accepted' => ['nullable', 'boolean'],
|
|
]);
|
|
|
|
$visit = $checkIn->checkIn($owner, $organization, [
|
|
...$validated,
|
|
'source' => $source,
|
|
'policies_accepted' => $validated['policies_accepted'] ?? true,
|
|
]);
|
|
|
|
return response()->json($visit->load(['visitor', 'host']), 201);
|
|
}
|
|
|
|
public function show(Request $request, Visit $visit): JsonResponse
|
|
{
|
|
$this->authorizeOwner($request, $visit);
|
|
|
|
return response()->json($visit->load(['visitor', 'host']));
|
|
}
|
|
|
|
public function checkOut(Request $request, Visit $visit, VisitCheckOutService $checkOut): JsonResponse
|
|
{
|
|
$this->authorizeOwner($request, $visit);
|
|
|
|
return response()->json($checkOut->checkOut($visit));
|
|
}
|
|
|
|
public function activate(Request $request, Visit $visit, VisitLifecycleService $lifecycle): JsonResponse
|
|
{
|
|
$this->authorizeOwner($request, $visit);
|
|
|
|
$visit = $lifecycle->checkInFromSchedule($visit);
|
|
|
|
return response()->json($visit->load(['visitor', 'host']));
|
|
}
|
|
|
|
public function approve(Request $request, Visit $visit, VisitLifecycleService $lifecycle): JsonResponse
|
|
{
|
|
$this->authorizeOwner($request, $visit);
|
|
|
|
$visit = $lifecycle->approve($visit);
|
|
|
|
return response()->json($visit->load(['visitor', 'host']));
|
|
}
|
|
|
|
public function cancel(Request $request, Visit $visit, VisitLifecycleService $lifecycle): JsonResponse
|
|
{
|
|
$this->authorizeOwner($request, $visit);
|
|
|
|
$validated = $request->validate([
|
|
'reason' => ['nullable', 'string', 'max:500'],
|
|
]);
|
|
|
|
return response()->json(
|
|
$lifecycle->cancel($visit, null, $validated['reason'] ?? null)->load(['visitor', 'host']),
|
|
);
|
|
}
|
|
}
|