getDashboardData($request); // 영업파트너 수당 정보 추가 $data = array_merge($data, $this->getCommissionData()); return view('sales.dashboard.index', $data); } /** * HTMX 부분 새로고침용 데이터 반환 */ public function refresh(Request $request): View { $data = $this->getDashboardData($request); return view('sales.dashboard.partials.data-container', $data); } /** * 대시보드 데이터 조회 */ private function getDashboardData(Request $request): array { // 기간 설정 $period = $request->input('period', 'month'); // month or custom $year = $request->input('year', now()->year); $month = $request->input('month', now()->month); // 기간 설정 모드일 경우 if ($period === 'custom') { $startDate = $request->input('start_date', now()->startOfMonth()->format('Y-m-d')); $endDate = $request->input('end_date', now()->format('Y-m-d')); } else { $startDate = now()->startOfMonth()->format('Y-m-d'); $endDate = now()->endOfMonth()->format('Y-m-d'); } $currentUserId = auth()->id(); $childrenIds = auth()->user()->children()->pluck('id')->toArray(); $partnerIds = array_merge([$currentUserId], $childrenIds); // 현재 사용자의 영업파트너 정보 조회 $partner = SalesPartner::where('user_id', $currentUserId)->first(); $partnerId = $partner?->id; // 나와 관련된 모든 수당 조회 (영업파트너로서 + 매니저로서) $myCommissionsAsPartner = $partnerId ? SalesCommission::forPartner($partnerId)->get() : collect(); $myCommissionsAsManager = SalesCommission::forManager($currentUserId)->get(); // 판매자(영업파트너) 수당 계산 $partnerCommissionTotal = $myCommissionsAsPartner->sum('partner_commission'); $partnerCommissionPaid = $myCommissionsAsPartner->where('status', SalesCommission::STATUS_PAID)->sum('partner_commission'); $partnerCommissionPending = $myCommissionsAsPartner->where('status', SalesCommission::STATUS_PENDING)->sum('partner_commission'); $partnerCommissionApproved = $myCommissionsAsPartner->where('status', SalesCommission::STATUS_APPROVED)->sum('partner_commission'); // 매니저 수당 계산 $managerCommissionTotal = $myCommissionsAsManager->sum('manager_commission'); $managerCommissionPaid = $myCommissionsAsManager->where('status', SalesCommission::STATUS_PAID)->sum('manager_commission'); $managerCommissionPending = $myCommissionsAsManager->where('status', SalesCommission::STATUS_PENDING)->sum('manager_commission'); $managerCommissionApproved = $myCommissionsAsManager->where('status', SalesCommission::STATUS_APPROVED)->sum('manager_commission'); // 총 수당 계산 (중복 제거: 동일 commission에서 partner + manager인 경우) $allCommissionIds = $myCommissionsAsPartner->pluck('id')->merge($myCommissionsAsManager->pluck('id'))->unique(); $totalContracts = $allCommissionIds->count(); // 통계 데이터 (실제 데이터) $totalMembershipFee = $myCommissionsAsPartner->sum('payment_amount') + $myCommissionsAsManager->sum('payment_amount'); $totalCommission = $partnerCommissionTotal + $managerCommissionTotal; $paidCommission = $partnerCommissionPaid + $managerCommissionPaid; $commissionRate = $totalCommission > 0 ? round(($paidCommission / $totalCommission) * 100, 1) : 0; $stats = [ 'total_membership_fee' => $totalMembershipFee, // 총 가입비 'total_commission' => $totalCommission, // 총 수당 'commission_rate' => $commissionRate, // 지급 완료 비율 'total_contracts' => $totalContracts, // 전체 건수 'pending_membership_approval' => $myCommissionsAsPartner->where('status', SalesCommission::STATUS_PENDING)->count() + $myCommissionsAsManager->where('status', SalesCommission::STATUS_PENDING)->count(), 'pending_payment_approval' => $myCommissionsAsPartner->where('status', SalesCommission::STATUS_APPROVED)->count() + $myCommissionsAsManager->where('status', SalesCommission::STATUS_APPROVED)->count(), ]; // 역할별 수당 상세 (실제 데이터) $commissionByRole = [ [ 'name' => '판매자', 'rate' => 20, 'amount' => $partnerCommissionTotal, 'paid' => $partnerCommissionPaid, 'pending' => $partnerCommissionPending, 'approved' => $partnerCommissionApproved, 'color' => 'green', ], [ 'name' => '관리자', 'rate' => 5, 'amount' => $managerCommissionTotal, 'paid' => $managerCommissionPaid, 'pending' => $managerCommissionPending, 'approved' => $managerCommissionApproved, 'color' => 'blue', ], [ 'name' => '협업지원금', 'rate' => null, // 메뉴당 2,000원 'amount' => null, // 가입비 완납 시 계산 'color' => 'purple', ], ]; // 총 가입비 대비 수당 비율 $totalCommissionRatio = $totalMembershipFee > 0 ? round(($totalCommission / $totalMembershipFee) * 100, 1) : 0; // 1) 내가 등록한 가망고객에서 전환된 tenant_id (20% 수당) $registeredTenantIds = TenantProspect::whereNotNull('tenant_id') ->where('status', TenantProspect::STATUS_CONVERTED) ->whereIn('registered_by', $partnerIds) ->pluck('tenant_id') ->toArray(); // 2) 내가 매니저로 지정된 tenant_id (5% 수당) $managedTenantIds = SalesTenantManagement::where('manager_user_id', $currentUserId) ->pluck('tenant_id') ->toArray(); // 두 목록 합치기 (중복 제거) $convertedTenantIds = array_unique(array_merge($registeredTenantIds, $managedTenantIds)); // 3) 내가 등록한 가망고객 (아직 전환되지 않은 것 - active 상태) $prospects = TenantProspect::whereIn('registered_by', $partnerIds) ->whereIn('status', [TenantProspect::STATUS_ACTIVE, TenantProspect::STATUS_EXPIRED]) ->orderBy('created_at', 'desc') ->get(); // 수익 및 테넌트 관리 통계 (실제 데이터) $tenantStats = [ 'total_tenants' => count($convertedTenantIds), // 관리 테넌트 'total_prospects' => $prospects->count(), // 진행중 가망고객 'total_membership_revenue' => $totalMembershipFee, // 총 가입비 실적 'total_commission_accumulated' => $totalCommission, // 누적 수당 'confirmed_commission' => $paidCommission, // 확정(지급완료) 수당 ]; // 전환된 테넌트만 조회 (최신순, 페이지네이션) $tenants = Tenant::whereIn('id', $convertedTenantIds) ->orderBy('created_at', 'desc') ->paginate(10) ->withQueryString(); // 각 테넌트의 영업 관리 정보 로드 $tenantIds = $tenants->pluck('id')->toArray(); $managements = SalesTenantManagement::whereIn('tenant_id', $tenantIds) ->with('manager') ->get() ->keyBy('tenant_id'); // 내가 유치한 영업파트너 목록 (드롭다운용) $allManagers = auth()->user()->children() ->where('is_active', true) ->get(['id', 'name', 'email']); return compact( 'stats', 'commissionByRole', 'totalCommissionRatio', 'tenantStats', 'tenants', 'prospects', 'managements', 'allManagers', 'period', 'year', 'month', 'startDate', 'endDate' ); } /** * 매니저 지정 변경 */ public function assignManager(int $tenantId, Request $request): JsonResponse { $request->validate([ 'manager_id' => 'required|integer', ]); $tenant = Tenant::findOrFail($tenantId); $managerId = $request->input('manager_id'); // 테넌트 영업 관리 정보 조회 또는 생성 $management = SalesTenantManagement::findOrCreateByTenant($tenantId); if ($managerId === 0) { // 본인으로 설정 (현재 로그인 사용자) $manager = auth()->user(); $management->update([ 'manager_user_id' => $manager->id, ]); } else { // 특정 매니저 지정 $manager = User::find($managerId); if (!$manager) { return response()->json([ 'success' => false, 'message' => '매니저를 찾을 수 없습니다.', ], 404); } $management->update([ 'manager_user_id' => $manager->id, ]); } return response()->json([ 'success' => true, 'manager' => [ 'id' => $manager->id, 'name' => $manager->name, ], ]); } /** * 테넌트 리스트 부분 새로고침 (HTMX) */ public function refreshTenantList(Request $request): View { // 테넌트 목록 (나와 연결된 계약만) $currentUserId = auth()->id(); $childrenIds = auth()->user()->children()->pluck('id')->toArray(); $partnerIds = array_merge([$currentUserId], $childrenIds); // 1) 내가 등록한 가망고객에서 전환된 tenant_id (20% 수당) $registeredTenantIds = TenantProspect::whereNotNull('tenant_id') ->where('status', TenantProspect::STATUS_CONVERTED) ->whereIn('registered_by', $partnerIds) ->pluck('tenant_id') ->toArray(); // 2) 내가 매니저로 지정된 tenant_id (5% 수당) $managedTenantIds = SalesTenantManagement::where('manager_user_id', $currentUserId) ->pluck('tenant_id') ->toArray(); // 두 목록 합치기 (중복 제거) $convertedTenantIds = array_unique(array_merge($registeredTenantIds, $managedTenantIds)); // 3) 내가 등록한 가망고객 (아직 전환되지 않은 것 - active 상태) $prospects = TenantProspect::whereIn('registered_by', $partnerIds) ->whereIn('status', [TenantProspect::STATUS_ACTIVE, TenantProspect::STATUS_EXPIRED]) ->orderBy('created_at', 'desc') ->get(); // 전환된 테넌트만 조회 (최신순, 페이지네이션) $tenants = Tenant::whereIn('id', $convertedTenantIds) ->orderBy('created_at', 'desc') ->paginate(10) ->withQueryString(); // 각 테넌트의 영업 관리 정보 로드 $tenantIds = $tenants->pluck('id')->toArray(); $managements = SalesTenantManagement::whereIn('tenant_id', $tenantIds) ->with('manager') ->get() ->keyBy('tenant_id'); // 내가 유치한 영업파트너 목록 (드롭다운용) $allManagers = auth()->user()->children() ->where('is_active', true) ->get(['id', 'name', 'email']); return view('sales.dashboard.partials.tenant-list', compact( 'tenants', 'prospects', 'managements', 'allManagers' )); } /** * 매니저 목록 조회 (드롭다운용) */ public function getManagers(Request $request): JsonResponse { // HQ 테넌트의 사용자 중 매니저 역할이 있는 사용자 조회 $managers = User::whereHas('tenants', function ($query) { $query->where('tenant_type', 'HQ'); })->get(['id', 'name', 'email']); return response()->json([ 'success' => true, 'managers' => $managers, ]); } /** * 유치 파트너 활동 현황 (HTMX 탭 로드) */ public function partnerActivity(Request $request): View { $data = $this->getPartnerActivityData(); return view('sales.dashboard.partials.partner-activity', $data); } /** * 유치 파트너 활동 데이터 조회 */ private function getPartnerActivityData(): array { $currentUser = auth()->user(); $currentUserId = $currentUser->id; // 직접 유치한 하위 파트너 목록 (parent_id가 현재 사용자인 사용자들) $recruitedPartners = User::where('parent_id', $currentUserId) ->where('is_active', true) ->with(['userRoles.role']) ->get(); $partnerIds = $recruitedPartners->pluck('id')->toArray(); // 요약 통계 계산 $summaryStats = $this->calculatePartnerSummaryStats($partnerIds, $currentUserId); // 파트너별 상세 활동 데이터 $partnerActivities = $this->getPartnerActivitiesDetail($recruitedPartners, $currentUserId); return [ 'summaryStats' => $summaryStats, 'partnerActivities' => $partnerActivities, 'recruitedPartners' => $recruitedPartners, ]; } /** * 유치 파트너 요약 통계 계산 */ private function calculatePartnerSummaryStats(array $partnerIds, int $currentUserId): array { // 유치 파트너 수 $partnerCount = count($partnerIds); // 하위 파트너들이 등록한 총 영업권(명함) 수 $totalProspects = TenantProspect::whereIn('registered_by', $partnerIds)->count(); // 하위 파트너들의 계약 성사 건수 $totalConversions = TenantProspect::whereIn('registered_by', $partnerIds) ->where('status', TenantProspect::STATUS_CONVERTED) ->count(); // 매니저로서 받을 수당 (내가 매니저로 지정된 수당 중 하위 파트너 관련) $expectedCommission = SalesCommission::where('manager_user_id', $currentUserId) ->whereHas('partner', function ($query) use ($partnerIds) { $query->whereIn('user_id', $partnerIds); }) ->sum('manager_commission'); return [ 'partner_count' => $partnerCount, 'total_prospects' => $totalProspects, 'total_conversions' => $totalConversions, 'expected_commission' => $expectedCommission, ]; } /** * 파트너별 상세 활동 데이터 */ private function getPartnerActivitiesDetail($recruitedPartners, int $currentUserId): array { $activities = []; foreach ($recruitedPartners as $partner) { // 파트너의 영업파트너 정보 $salesPartner = SalesPartner::where('user_id', $partner->id)->first(); // 파트너가 등록한 영업권 수 $prospectCount = TenantProspect::where('registered_by', $partner->id)->count(); // 진행 중인 영업권 (active 상태) $activeProspects = TenantProspect::where('registered_by', $partner->id) ->where('status', TenantProspect::STATUS_ACTIVE) ->count(); // 계약 성사 건수 $conversions = TenantProspect::where('registered_by', $partner->id) ->where('status', TenantProspect::STATUS_CONVERTED) ->count(); // 이 파트너로 인한 나의 매니저 수당 $managerCommission = 0; if ($salesPartner) { $managerCommission = SalesCommission::where('manager_user_id', $currentUserId) ->where('partner_id', $salesPartner->id) ->sum('manager_commission'); } // 최근 활동 내역 (최근 전환된 테넌트 5개) $recentTenants = TenantProspect::where('registered_by', $partner->id) ->where('status', TenantProspect::STATUS_CONVERTED) ->with(['tenant']) ->orderBy('converted_at', 'desc') ->limit(5) ->get(); // 활동 상태 판단 $lastActivity = TenantProspect::where('registered_by', $partner->id) ->orderBy('updated_at', 'desc') ->first(); $status = 'inactive'; if ($lastActivity) { $daysSinceActivity = now()->diffInDays($lastActivity->updated_at); if ($daysSinceActivity <= 7) { $status = 'active'; } elseif ($daysSinceActivity <= 30) { $status = 'moderate'; } } // 역할 정보 $roles = $partner->userRoles->pluck('role.name')->filter()->toArray(); $roleLabel = !empty($roles) ? implode(', ', $roles) : '영업'; $activities[] = [ 'partner' => $partner, 'role_label' => $roleLabel, 'prospect_count' => $prospectCount, 'active_prospects' => $activeProspects, 'conversions' => $conversions, 'manager_commission' => $managerCommission, 'status' => $status, 'recent_tenants' => $recentTenants, ]; } return $activities; } /** * 영업파트너 수당 정보 조회 */ private function getCommissionData(): array { $user = auth()->user(); $commissionSummary = []; $recentCommissions = collect(); // 현재 사용자가 영업파트너인지 확인 $partner = SalesPartner::where('user_id', $user->id) ->where('status', 'active') ->first(); if ($partner) { $commissionSummary = $this->commissionService->getPartnerCommissionSummary($partner->id); $recentCommissions = $this->commissionService->getRecentCommissions($partner->id, 5); } return compact('commissionSummary', 'recentCommissions', 'partner'); } /** * 영업파트너 가이드북 도움말 모달 */ public function helpGuide(): View { // 가이드북 마크다운 파일 읽기 (resources/markdown 폴더) $guidePath = resource_path('markdown/영업파트너가이드북.md'); if (file_exists($guidePath)) { $markdown = file_get_contents($guidePath); $htmlContent = Str::markdown($markdown); } else { $htmlContent = '

가이드북을 찾을 수 없습니다.

'; } return view('sales.dashboard.partials.help-modal', compact('htmlContent')); } }