$data['user_id'] ?? null, 'name' => $data['name'], 'email' => $data['email'], 'phone' => $data['phone'] ?? null, 'password' => Hash::make($data['password']), 'is_active' => false, // 승인 전까지 비활성 'parent_id' => $data['parent_id'] ?? null, 'approval_status' => 'pending', // 승인 대기 상태 'must_change_password' => true, ]); // 2. 테넌트 연결 $user->tenants()->attach($tenantId, [ 'is_active' => true, 'is_default' => true, 'joined_at' => now(), ]); // 3. 역할 할당 if (!empty($data['role_ids'])) { $this->syncRoles($user, $tenantId, $data['role_ids']); } // 4. 부서 할당 if (!empty($data['department_ids'])) { $this->syncDepartments($user, $tenantId, $data['department_ids']); } // 5. 첨부 서류 저장 if (!empty($documents)) { $this->uploadDocuments($user, $tenantId, $documents); } return $user; }); } /** * 영업담당자 수정 */ public function updateSalesManager(User $user, array $data, array $documents = []): User { return DB::transaction(function () use ($user, $data, $documents) { $tenantId = session('selected_tenant_id', 1); // 1. 기본 정보 업데이트 $updateData = [ 'name' => $data['name'], 'email' => $data['email'], 'phone' => $data['phone'] ?? null, 'parent_id' => $data['parent_id'] ?? null, ]; // 비밀번호 변경 시에만 업데이트 if (!empty($data['password'])) { $updateData['password'] = Hash::make($data['password']); } $user->update($updateData); // 2. 역할 동기화 if (isset($data['role_ids'])) { $this->syncRoles($user, $tenantId, $data['role_ids']); } // 3. 부서 동기화 if (isset($data['department_ids'])) { $this->syncDepartments($user, $tenantId, $data['department_ids']); } // 4. 새 첨부 서류 저장 if (!empty($documents)) { $this->uploadDocuments($user, $tenantId, $documents); } return $user->fresh(); }); } /** * 영업담당자 승인 */ public function approve(User $user, int $approverId): User { $user->update([ 'approval_status' => 'approved', 'approved_by' => $approverId, 'approved_at' => now(), 'is_active' => true, 'rejection_reason' => null, ]); return $user; } /** * 영업담당자 반려 */ public function reject(User $user, int $approverId, string $reason): User { $user->update([ 'approval_status' => 'rejected', 'approved_by' => $approverId, 'approved_at' => now(), 'rejection_reason' => $reason, 'is_active' => false, ]); return $user; } /** * 역할 동기화 */ public function syncRoles(User $user, int $tenantId, array $roleIds): void { // 기존 역할 삭제 UserRole::withTrashed() ->where('user_id', $user->id) ->where('tenant_id', $tenantId) ->forceDelete(); // 새 역할 추가 foreach ($roleIds as $roleId) { UserRole::create([ 'user_id' => $user->id, 'tenant_id' => $tenantId, 'role_id' => $roleId, 'assigned_at' => now(), ]); } } /** * 부서 동기화 */ public function syncDepartments(User $user, int $tenantId, array $departmentIds): void { // 기존 부서 삭제 DepartmentUser::withTrashed() ->where('user_id', $user->id) ->where('tenant_id', $tenantId) ->forceDelete(); // 새 부서 추가 foreach ($departmentIds as $index => $departmentId) { DepartmentUser::create([ 'user_id' => $user->id, 'tenant_id' => $tenantId, 'department_id' => $departmentId, 'is_primary' => $index === 0, 'joined_at' => now(), 'created_by' => auth()->id(), ]); } } /** * 서류 업로드 */ public function uploadDocuments(User $user, int $tenantId, array $documents): array { $uploaded = []; foreach ($documents as $doc) { if (!isset($doc['file']) || !$doc['file'] instanceof UploadedFile) { continue; } $file = $doc['file']; $documentType = $doc['document_type'] ?? 'other'; $description = $doc['description'] ?? null; // 파일 저장 $storedName = Str::uuid() . '.' . $file->getClientOriginalExtension(); $filePath = "sales-managers/{$user->id}/{$storedName}"; Storage::disk('tenant')->put($filePath, file_get_contents($file)); // DB 저장 $document = SalesManagerDocument::create([ 'tenant_id' => $tenantId, 'user_id' => $user->id, 'file_path' => $filePath, 'original_name' => $file->getClientOriginalName(), 'stored_name' => $storedName, 'mime_type' => $file->getMimeType(), 'file_size' => $file->getSize(), 'document_type' => $documentType, 'description' => $description, 'uploaded_by' => auth()->id(), ]); $uploaded[] = $document; } return $uploaded; } /** * 서류 삭제 */ public function deleteDocument(SalesManagerDocument $document): bool { // 물리 파일 삭제 if ($document->existsInStorage()) { Storage::disk('tenant')->delete($document->file_path); } // DB 삭제 $document->deleted_by = auth()->id(); $document->save(); return $document->delete(); } /** * 영업담당자 목록 조회 (역할 기반) */ public function getSalesManagers(array $filters = []) { $tenantId = session('selected_tenant_id', 1); // 영업관련 역할을 가진 사용자 조회 $query = User::query() ->whereHas('userRoles', function ($q) use ($tenantId) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) { $rq->whereIn('name', ['sales_operator', 'sales_admin', 'sales_manager']); }); }) ->with(['parent', 'userRoles.role', 'salesDocuments']); // 검색 if (!empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('user_id', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%") ->orWhere('phone', 'like', "%{$search}%"); }); } // 역할 필터 if (!empty($filters['role'])) { $roleName = $filters['role']; $query->whereHas('userRoles', function ($q) use ($tenantId, $roleName) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) use ($roleName) { $rq->where('name', $roleName); }); }); } // 승인 상태 필터 if (!empty($filters['approval_status'])) { $query->where('approval_status', $filters['approval_status']); } return $query->orderBy('name'); } /** * 상위 관리자 목록 (운영자, 영업관리) */ public function getParentCandidates(?int $excludeId = null) { $tenantId = session('selected_tenant_id', 1); $query = User::query() ->where('is_active', true) ->where('approval_status', 'approved') ->whereHas('userRoles', function ($q) use ($tenantId) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) { $rq->whereIn('name', ['sales_operator', 'sales_admin']); }); }); if ($excludeId) { $query->where('id', '!=', $excludeId); } return $query->orderBy('name')->get(); } /** * 통계 조회 */ public function getStats(): array { $tenantId = session('selected_tenant_id', 1); $baseQuery = User::query() ->whereHas('userRoles', function ($q) use ($tenantId) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) { $rq->whereIn('name', ['sales_operator', 'sales_admin', 'sales_manager']); }); }); return [ 'total' => (clone $baseQuery)->count(), 'pending' => (clone $baseQuery)->where('approval_status', 'pending')->count(), 'approved' => (clone $baseQuery)->where('approval_status', 'approved')->count(), 'operators' => (clone $baseQuery) ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales_operator')) ->count(), 'sales_admins' => (clone $baseQuery) ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales_admin')) ->count(), 'managers' => (clone $baseQuery) ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales_manager')) ->count(), ]; } }