withTrashed()->with('parent'); // Tenant 필터링 (선택된 경우에만) if ($tenantId) { $query->where('tenant_id', $tenantId); } // Soft Delete 필터 if (isset($filters['trashed'])) { if ($filters['trashed'] === 'only') { $query->onlyTrashed(); } elseif ($filters['trashed'] === 'with') { $query->withTrashed(); } } // 검색 필터 if (! empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('code', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%"); }); } // 활성 상태 필터 if (isset($filters['is_active'])) { $query->where('is_active', $filters['is_active']); } // 정렬 $sortBy = $filters['sort_by'] ?? 'sort_order'; $sortDirection = $filters['sort_direction'] ?? 'asc'; $query->orderBy($sortBy, $sortDirection); return $query->paginate($perPage); } /** * 특정 부서 조회 */ public function getDepartmentById(int $id): ?Department { $tenantId = session('selected_tenant_id'); $query = Department::query()->with(['parent', 'children']); // Tenant 필터링 (선택된 경우에만) if ($tenantId) { $query->where('tenant_id', $tenantId); } return $query->find($id); } /** * 부서 생성 */ public function createDepartment(array $data): Department { $tenantId = session('selected_tenant_id'); $department = Department::create([ 'tenant_id' => $tenantId, 'parent_id' => $data['parent_id'] ?? null, 'code' => $data['code'], 'name' => $data['name'], 'description' => $data['description'] ?? null, 'is_active' => $data['is_active'] ?? true, 'sort_order' => $data['sort_order'] ?? 0, 'created_by' => auth()->id(), ]); return $department->fresh(['parent']); } /** * 부서 수정 */ public function updateDepartment(int $id, array $data): bool { $department = $this->getDepartmentById($id); if (! $department) { return false; } // 자기 자신을 상위 부서로 설정하는 것 방지 if (isset($data['parent_id']) && $data['parent_id'] == $id) { return false; } $updated = $department->update([ 'parent_id' => $data['parent_id'] ?? $department->parent_id, 'code' => $data['code'] ?? $department->code, 'name' => $data['name'] ?? $department->name, 'description' => $data['description'] ?? $department->description, 'is_active' => $data['is_active'] ?? $department->is_active, 'sort_order' => $data['sort_order'] ?? $department->sort_order, 'updated_by' => auth()->id(), ]); return $updated; } /** * 부서 삭제 (Soft Delete) */ public function deleteDepartment(int $id): bool { $department = $this->getDepartmentById($id); if (! $department) { return false; } // 하위 부서가 있는 경우 삭제 불가 if ($department->children()->count() > 0) { return false; } $department->deleted_by = auth()->id(); $department->save(); return $department->delete(); } /** * 부서 복원 */ public function restoreDepartment(int $id): bool { $tenantId = session('selected_tenant_id'); $query = Department::onlyTrashed(); if ($tenantId) { $query->where('tenant_id', $tenantId); } $department = $query->find($id); if (! $department) { return false; } return $department->restore(); } /** * 부서 영구 삭제 */ public function forceDeleteDepartment(int $id): bool { $tenantId = session('selected_tenant_id'); $query = Department::withTrashed(); if ($tenantId) { $query->where('tenant_id', $tenantId); } $department = $query->find($id); if (! $department) { return false; } // 하위 부서가 있는 경우 삭제 불가 if ($department->children()->count() > 0) { return false; } return $department->forceDelete(); } /** * 부서 코드 중복 체크 */ public function isCodeExists(string $code, ?int $excludeId = null): bool { $tenantId = session('selected_tenant_id'); $query = Department::where('tenant_id', $tenantId) ->where('code', $code); if ($excludeId) { $query->where('id', '!=', $excludeId); } return $query->exists(); } /** * 활성 부서 목록 (드롭다운용) */ public function getActiveDepartments(): Collection { $tenantId = session('selected_tenant_id'); $query = Department::query()->where('is_active', true); // Tenant 필터링 (선택된 경우에만) if ($tenantId) { $query->where('tenant_id', $tenantId); } return $query->orderBy('sort_order')->orderBy('name')->get(['id', 'parent_id', 'code', 'name']); } /** * 부서 통계 */ public function getDepartmentStats(): array { $tenantId = session('selected_tenant_id'); $baseQuery = Department::query(); // Tenant 필터링 (선택된 경우에만) if ($tenantId) { $baseQuery->where('tenant_id', $tenantId); } return [ 'total' => (clone $baseQuery)->count(), 'active' => (clone $baseQuery)->where('is_active', true)->count(), 'inactive' => (clone $baseQuery)->where('is_active', false)->count(), ]; } }