supervisor(); $baseQuery = Establishment::query() ->where('organization_id', $supervisor->organization_id); if ($supervisor->establishment_id !== null) { $baseQuery->where('id', $supervisor->establishment_id); } $totalCount = (clone $baseQuery)->count(); $viewMode = $totalCount === 1 ? 'single' : 'list'; $canManageEstablishments = $this->canManageEstablishments(); $canCreateEstablishments = $this->canCreateEstablishments(); if ($viewMode === 'single') { $establishment = (clone $baseQuery)->withCount('machines')->first(); return Inertia::render('Supervisor/Organizations/Index', [ 'establishments' => [$this->formatEstablishment($establishment)], 'viewMode' => 'single', 'canManageEstablishments' => $canManageEstablishments, 'canCreateEstablishments' => $canCreateEstablishments, 'filters' => [], ]); } $query = (clone $baseQuery)->withCount('machines'); if ($request->filled('search')) { $search = $request->string('search'); $query->where(function ($builder) use ($search) { $builder->where('name', 'like', "%{$search}%") ->orWhere('address', 'like', "%{$search}%") ->orWhere('city', 'like', "%{$search}%") ->orWhere('zip_code', 'like', "%{$search}%"); }); } if ($request->has('is_active') && $request->string('is_active')->toString() !== '') { $query->where('is_active', $request->boolean('is_active')); } $establishments = $query ->tap(fn ($builder) => $this->applySort($request, $builder, [ 'name' => 'name', 'city' => 'city', 'machines_count' => 'machines_count', 'is_active' => 'is_active', ], 'name', 'asc')) ->paginate($this->supervisorListPerPage($request)) ->withQueryString() ->through(fn (Establishment $establishment) => $this->formatEstablishment($establishment)); return Inertia::render('Supervisor/Organizations/Index', [ 'establishments' => $establishments, 'viewMode' => 'list', 'canManageEstablishments' => $canManageEstablishments, 'canCreateEstablishments' => $canCreateEstablishments, 'filters' => [ 'search' => $request->string('search')->toString() ?: null, 'is_active' => $request->has('is_active') && $request->string('is_active')->toString() !== '' ? ($request->boolean('is_active') ? '1' : '0') : null, 'sort' => $request->string('sort')->toString() ?: 'name', 'direction' => $request->string('direction')->toString() === 'desc' ? 'desc' : 'asc', 'per_page' => $this->supervisorListPerPage($request), ], ]); } public function searchAddresses(Request $request): JsonResponse { abort_unless($this->canManageEstablishments(), 403); $validated = $request->validate([ 'q' => ['required', 'string', 'min:3', 'max:200'], ]); return response()->json( $this->geocoding->search($validated['q']), ); } public function storeEstablishment(Request $request): RedirectResponse { abort_unless($this->canManageEstablishments(), 403); abort_if($this->supervisor()->establishment_id !== null, 403); $validated = $this->prepareEstablishmentData( $request->validate($this->establishmentRules()), ); $validated['organization_id'] = $this->supervisor()->organization_id; Establishment::query()->create($validated); return redirect()->route('supervisor.organizations.index') ->with('success', 'Enseigne créée.'); } public function updateEstablishment(Request $request, int $id): RedirectResponse { abort_unless($this->canManageEstablishments(), 403); $establishment = $this->findAccessibleEstablishment($id); $validated = $this->prepareEstablishmentData( $request->validate($this->establishmentRules()), ); if (! empty($validated['is_active']) && ! $establishment->is_active) { $this->validateEstablishmentReadyForActivation($validated, $establishment); } $establishment->update($validated); return redirect()->route('supervisor.organizations.index') ->with('success', 'Enseigne mise à jour.'); } public function toggleEstablishmentActive(int $id): RedirectResponse { abort_unless($this->canManageEstablishments(), 403); $establishment = $this->findAccessibleEstablishment($id); $isActive = ! $establishment->is_active; if ($isActive) { $this->validateEstablishmentReadyForActivation([ 'name' => $establishment->name, 'address' => $establishment->address, 'timezone' => $establishment->timezone, ], $establishment); } $establishment->update(['is_active' => $isActive]); return redirect()->route('supervisor.organizations.index') ->with('success', $isActive ? 'Enseigne réactivée.' : 'Enseigne désactivée.'); } /** * @return array */ private function formatEstablishment(Establishment $establishment): array { return [ 'id' => $establishment->id, 'uuid' => $establishment->uuid, 'name' => $establishment->name, 'address' => $establishment->address, 'city' => $establishment->city, 'zip_code' => $establishment->zip_code, 'latitude' => $establishment->latitude !== null ? (float) $establishment->latitude : null, 'longitude' => $establishment->longitude !== null ? (float) $establishment->longitude : null, 'timezone' => $establishment->timezone, 'is_active' => $establishment->is_active, 'machines_count' => $establishment->machines_count, ]; } /** * @return array */ private function establishmentRules(): array { return [ 'name' => ['required', 'string', 'max:200'], 'address' => ['required', 'string'], 'city' => ['nullable', 'string', 'max:100'], 'zip_code' => ['nullable', 'string', 'max:10'], 'timezone' => ['required', 'string', 'max:50'], 'is_active' => ['boolean'], ]; } /** * @param array $validated * @return array */ private function prepareEstablishmentData(array $validated): array { $coordinates = $this->geocoding->geocode( $validated['address'], $validated['city'] ?? null, $validated['zip_code'] ?? null, ); $validated['latitude'] = $coordinates['latitude'] ?? null; $validated['longitude'] = $coordinates['longitude'] ?? null; return $validated; } private function findAccessibleEstablishment(int $id): Establishment { $supervisor = $this->supervisor(); return Establishment::query() ->where('id', $id) ->where('organization_id', $supervisor->organization_id) ->when($supervisor->establishment_id, fn ($query) => $query->where('id', $supervisor->establishment_id)) ->firstOrFail(); } private function canCreateEstablishments(): bool { $supervisor = $this->supervisor(); if ($supervisor->role === 'viewer') { return false; } return in_array($supervisor->role, ['owner', 'platform_admin'], true) && $supervisor->establishment_id === null; } private function canManageEstablishments(): bool { return $this->supervisor()->role !== 'viewer'; } /** * @param array $data */ private function validateEstablishmentReadyForActivation(array $data, Establishment $establishment): void { $validator = validator( $data, [ 'name' => ['required', 'string', 'max:200'], 'address' => ['required', 'string'], 'timezone' => ['required', 'string', 'max:50'], ], [ 'name.required' => 'Le nom est requis pour réactiver l\'enseigne.', 'address.required' => 'L\'adresse est requise pour réactiver l\'enseigne.', 'timezone.required' => 'Le fuseau horaire est requis pour réactiver l\'enseigne.', ], ); if ($validator->fails()) { throw ValidationException::withMessages($validator->errors()->toArray()); } $establishment->loadMissing('organization'); if (! $establishment->organization?->is_active) { throw ValidationException::withMessages([ 'is_active' => 'L\'organisation doit être active pour réactiver cette enseigne.', ]); } } }