user()->isAdmin() && !auth()->user()->isSuperAdmin()) { abort(403, '관리자만 접근할 수 있습니다.'); } } /** * 전체 고객 목록 페이지 */ public function index(Request $request): View|Response { $this->checkAdminAccess(); if ($request->header('HX-Request')) { return response('', 200)->header('HX-Redirect', route('sales.admin-prospects.index')); } $data = $this->getIndexData($request); return view('sales.admin-prospects.index', $data); } /** * 고객 상세 모달 */ public function modalShow(int $id): View { $this->checkAdminAccess(); $prospect = TenantProspect::with(['registeredBy', 'tenant'])->findOrFail($id); // 진행률 $progress = SalesScenarioChecklist::getProspectProgress($prospect->id); $prospect->sales_progress = $progress['sales']['percentage']; $prospect->manager_progress = $progress['manager']['percentage']; // management 정보 $management = SalesTenantManagement::findOrCreateByProspect($prospect->id); return view('sales.admin-prospects.partials.show-modal', compact('prospect', 'management', 'progress')); } /** * 콘텐츠 새로고침 (HTMX) */ public function refresh(Request $request): View { $this->checkAdminAccess(); $data = $this->getIndexData($request); return view('sales.admin-prospects.partials.content', $data); } /** * index 데이터 조회 (공통) */ private function getIndexData(Request $request): array { // 영업 역할을 가진 사용자 목록 (영업파트너) $salesPartners = User::whereHas('userRoles', function ($q) { $q->whereHas('role', function ($rq) { $rq->whereIn('name', ['sales', 'manager']); }); })->orderBy('name')->get(); // 필터 $filters = [ 'search' => $request->get('search'), 'status' => $request->get('status'), 'registered_by' => $request->get('registered_by'), ]; // 쿼리 빌드 $query = TenantProspect::with(['registeredBy', 'tenant']); // 검색 if (!empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('company_name', 'like', "%{$search}%") ->orWhere('business_number', 'like', "%{$search}%") ->orWhere('ceo_name', 'like', "%{$search}%") ->orWhere('contact_phone', 'like', "%{$search}%"); }); } // 상태 필터 if (!empty($filters['status'])) { $query->where('status', $filters['status']); } // 영업파트너 필터 if (!empty($filters['registered_by'])) { $query->where('registered_by', $filters['registered_by']); } $prospects = $query->orderByDesc('created_at')->paginate(20); // 각 가망고객의 진행률 계산 및 상태 자동 전환 foreach ($prospects as $prospect) { $progress = SalesScenarioChecklist::getProspectProgress($prospect->id); $prospect->sales_progress = $progress['sales']['percentage']; $prospect->manager_progress = $progress['manager']['percentage']; // 진행률 100% 시 상태 자동 전환 체크 if ($progress['sales']['percentage'] === 100 && $progress['manager']['percentage'] === 100) { SalesScenarioChecklist::checkAndConvertProspectStatus($prospect->id); $prospect->refresh(); } // management 정보 $management = SalesTenantManagement::where('tenant_prospect_id', $prospect->id)->first(); $prospect->hq_status = $management?->hq_status ?? 'pending'; $prospect->hq_status_label = $management?->hq_status_label ?? '대기'; $prospect->manager_user = $management?->manager; // 수당 정보 (management가 있는 경우) if ($management) { $commission = SalesCommission::where('management_id', $management->id)->first(); $prospect->commission = $commission; } else { $prospect->commission = null; } } // 전체 통계 $stats = [ 'total' => TenantProspect::count(), 'active' => TenantProspect::where('status', TenantProspect::STATUS_ACTIVE)->count(), 'expired' => TenantProspect::where('status', TenantProspect::STATUS_EXPIRED)->count(), 'converted' => TenantProspect::where('status', TenantProspect::STATUS_CONVERTED)->count(), ]; // 영업파트너별 통계 $partnerStats = TenantProspect::selectRaw('registered_by, COUNT(*) as total') ->groupBy('registered_by') ->with('registeredBy') ->get() ->map(function ($item) { return [ 'user' => $item->registeredBy, 'total' => $item->total, ]; }); return compact('prospects', 'stats', 'salesPartners', 'partnerStats', 'filters'); } /** * 개발 진행 상태 변경 */ public function updateHqStatus(int $id, Request $request) { $this->checkAdminAccess(); $request->validate([ 'hq_status' => 'required|in:' . implode(',', array_keys(SalesTenantManagement::$hqStatusLabels)), ]); $prospect = TenantProspect::findOrFail($id); $management = SalesTenantManagement::findOrCreateByProspect($prospect->id); $management->update([ 'hq_status' => $request->input('hq_status'), ]); return response()->json([ 'success' => true, 'hq_status' => $management->hq_status, 'hq_status_label' => $management->hq_status_label, ]); } /** * 수당 날짜 기록/수정 */ public function updateCommissionDate(int $id, Request $request) { $this->checkAdminAccess(); $request->validate([ 'field' => 'required|in:first_payment_at,first_partner_paid_at,second_payment_at,second_partner_paid_at,first_subscription_at,manager_paid_at', 'date' => 'nullable|date', ]); $prospect = TenantProspect::findOrFail($id); $management = SalesTenantManagement::findOrCreateByProspect($prospect->id); // Commission 레코드 조회 또는 생성 $commission = SalesCommission::firstOrCreate( ['management_id' => $management->id], [ 'tenant_id' => $prospect->tenant_id ?? 1, 'payment_type' => 'deposit', 'payment_amount' => 0, 'payment_date' => now(), 'base_amount' => 0, 'partner_rate' => 0, 'manager_rate' => 0, 'partner_commission' => 0, 'manager_commission' => 0, 'scheduled_payment_date' => now()->addMonth()->day(10), 'status' => SalesCommission::STATUS_PENDING, 'partner_id' => $management->sales_partner_id ?? 0, 'manager_user_id' => $management->manager_user_id, ] ); $field = $request->input('field'); $date = $request->input('date') ?: now()->format('Y-m-d'); $commission->update([ $field => $date, ]); return response()->json([ 'success' => true, 'field' => $field, 'date' => $commission->$field?->format('Y-m-d'), 'date_display' => $commission->$field?->format('m/d'), ]); } /** * 수당 날짜 삭제 (초기화) */ public function clearCommissionDate(int $id, Request $request) { $this->checkAdminAccess(); $request->validate([ 'field' => 'required|in:first_payment_at,first_partner_paid_at,second_payment_at,second_partner_paid_at,first_subscription_at,manager_paid_at', ]); $prospect = TenantProspect::findOrFail($id); $management = SalesTenantManagement::where('tenant_prospect_id', $prospect->id)->first(); if (!$management) { return response()->json(['success' => false, 'message' => '관리 정보가 없습니다.']); } $commission = SalesCommission::where('management_id', $management->id)->first(); if (!$commission) { return response()->json(['success' => false, 'message' => '수당 정보가 없습니다.']); } $field = $request->input('field'); $commission->update([$field => null]); return response()->json([ 'success' => true, 'field' => $field, ]); } }