load('units'); } public function getAll(): Collection { return User::with(['state', 'units', 'userType'])->orderBy('name')->get(); } public function getAllByUnit(): Collection { $unitId = request()->input('active_unit_id') ?? Auth::user()->units->first()?->id; if (!$unitId) { return User::with(['state', 'units', 'userType'])->whereNull('id')->get(); } return User::with(['state', 'units', 'userType']) ->whereHas('units', fn($q) => $q->where('units.id', $unitId)) ->orderBy('name') ->get(); } public function findById(int $id): ?User { return User::with(['state', 'units', 'userType'])->find($id); } public function create(array $data): User { // Suporta unit_ids[] (múltiplas) ou unit_id (retrocompatibilidade) $unitIds = $data['unit_ids'] ?? null; if (empty($unitIds) && isset($data['unit_id'])) { $unitIds = array_filter([$data['unit_id']]); } if (empty($unitIds) && ($data['access_scope'] ?? 'unit') === 'unit') { $fallback = Auth::user()->units->first()?->id; $unitIds = $fallback ? [$fallback] : []; } unset($data['unit_ids'], $data['unit_id']); $role = $this->resolveRole($data, $unitIds[0] ?? null); unset($data['user_type_id']); $data['user_type'] = $role?->slug ?? $data['user_type']; $data['franchisor_user_type_id'] = ($data['access_scope'] ?? 'unit') === 'franchisor' ? $role?->id : null; $data = $this->handleAvatar($data); $user = User::create($data); if (!empty($unitIds)) { $this->syncUnitRoles($user, $unitIds, $data['user_type']); } return $user->load('state', 'units'); } public function update(int $id, array $data): ?User { $model = $this->findById($id); if (!$model) { return null; } // Suporta unit_ids[] (múltiplas) com fallback para unit_id (retrocompatibilidade) $hasUnitIds = array_key_exists('unit_ids', $data); $unitIds = $data['unit_ids'] ?? null; $hasUnitId = array_key_exists('unit_id', $data); $unitId = $data['unit_id'] ?? null; unset($data['unit_ids'], $data['unit_id']); $targetUnitId = $unitIds[0] ?? $unitId; $role = $this->resolveRole($data, $targetUnitId, $model); unset($data['user_type_id']); if ($role) { $data['user_type'] = $role->slug; $data['franchisor_user_type_id'] = ($data['access_scope'] ?? $model->access_scope) === 'franchisor' ? $role->id : null; } $data = $this->handleAvatar($data, $model->avatar_url); $model->update($data); if (($data['access_scope'] ?? $model->access_scope) === 'franchisor') { $model->units()->sync([]); } elseif ($hasUnitIds) { $this->syncUnitRoles($model, array_filter($unitIds ?? []), $data['user_type'] ?? $model->user_type); } elseif ($hasUnitId) { $this->syncUnitRoles($model, $unitId ? [$unitId] : [], $data['user_type'] ?? $model->user_type); } return $model->fresh(['state', 'units']); } public function delete(int $id): bool { $model = $this->findById($id); if (!$model) { return false; } if ($model->avatar_url) { Storage::delete($model->avatar_url); } return $model->delete(); } public function getUserTypes(): \Illuminate\Database\Eloquent\Collection { $scope = request()->input('access_scope', Auth::user()?->access_scope); $unitId = request()->input('active_unit_id') ?? Auth::user()?->units()->value('units.id'); return \App\Models\UserType::query() ->when($scope === 'unit', fn ($query) => $query->where('unit_id', $unitId)) ->when($scope === 'franchisor', fn ($query) => $query->whereNull('unit_id')) ->orderBy('label') ->get(); } private function handleAvatar(array $data, ?string $oldAvatarPath = null): array { if (!isset($data['avatar'])) { return $data; } if ($data['avatar'] instanceof UploadedFile) { if ($oldAvatarPath) { Storage::delete($oldAvatarPath); } $data['avatar_url'] = $data['avatar']->store('users/avatars'); } elseif (is_null($data['avatar'])) { if ($oldAvatarPath) { Storage::delete($oldAvatarPath); } $data['avatar_url'] = null; } unset($data['avatar']); return $data; } private function resolveRole(array $data, ?int $unitId, ?User $user = null): ?\App\Models\UserType { if (!empty($data['user_type_id'])) { return \App\Models\UserType::find($data['user_type_id']); } $slug = $data['user_type'] ?? $user?->user_type; $scope = $data['access_scope'] ?? $user?->access_scope; $type = \App\Models\UserType::query() ->where('slug', $slug) ->when($scope === 'unit', fn ($query) => $query->where('unit_id', $unitId)) ->when($scope === 'franchisor', fn ($query) => $query->whereNull('unit_id')) ->first(); abort_if(!$type, 422, 'O perfil não pertence ao contexto selecionado.'); return $type; } private function syncUnitRoles(User $user, array $unitIds, string $slug): void { $roles = \App\Models\UserType::query() ->whereIn('unit_id', $unitIds) ->where('slug', $slug) ->pluck('id', 'unit_id'); abort_if($roles->count() !== count($unitIds), 422, 'O perfil precisa existir em todas as unidades selecionadas.'); $user->units()->sync(collect($unitIds)->mapWithKeys( fn ($id) => [$id => ['user_type_id' => $roles[$id]]], )->all()); } }