moduleUtil = $moduleUtil; $this->callQueueService = $callQueueService; $this->companyProfileService = $companyProfileService; $this->completionService = $completionService; } protected function authorizeAccess(): void { $business_id = request()->session()->get('user.business_id'); TelemarketingUtil::authorizeTelemarketing($this->moduleUtil, $business_id, 'crm.telemarketing.access'); } public function index() { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id'); if (! TelemarketingUtil::isEnabled($business_id)) { return redirect()->action([CrmSettingsController::class, 'index']) ->with('status', ['success' => 0, 'msg' => __('crm::lang.enable_telemarketing_first')]); } $activeSession = $this->callQueueService->getActiveSession($business_id, auth()->id()); $activeQueue = empty($activeSession) ? $this->callQueueService->getActiveQueue($business_id, auth()->id()) : $activeSession->queue; $script = CrmCallScript::where('business_id', $business_id)->where('is_default', true)->first(); if (empty($script)) { $script = CrmCallScript::where('business_id', $business_id)->latest()->first(); } $scripts = CrmCallScript::where('business_id', $business_id)->get(); $statuses = CrmPhoneFollowUp::statusDropdown(); $outcomes = CrmCallSession::outcomes(); $sentiments = CrmCallAssessment::sentiments(); $contactRoles = CrmCompanyContact::roles(); $companyTypes = CrmCompany::companyTypes(); $requirementTypes = CrmCompanyRequirement::requirementTypes(); $objections = $this->objectionOptions(); $partnerPotentials = ['none' => __('crm::lang.partner_none'), 'low' => __('crm::lang.partner_low'), 'medium' => __('crm::lang.partner_medium'), 'high' => __('crm::lang.partner_high')]; $workspaceStats = $this->buildWorkspaceStats($business_id, auth()->id()); $crm_settings = TelemarketingUtil::mergeSettings((new \Modules\Crm\Utils\CrmUtil())->getCrmSettings($business_id)); return view('crm::telemarketing.workspace')->with(compact( 'activeSession', 'activeQueue', 'script', 'scripts', 'statuses', 'outcomes', 'sentiments', 'contactRoles', 'companyTypes', 'requirementTypes', 'objections', 'partnerPotentials', 'workspaceStats', 'crm_settings' )); } public function workspaceStats() { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id'); return response()->json($this->buildWorkspaceStats($business_id, auth()->id())); } protected function buildWorkspaceStats(int $business_id, int $user_id): array { $today = Carbon::today(); $this->callQueueService->syncQueueForBusiness($business_id); $todaySessions = CrmCallSession::where('business_id', $business_id) ->where('user_id', $user_id) ->whereDate('started_at', $today) ->get(); $settings = TelemarketingUtil::mergeSettings((new \Modules\Crm\Utils\CrmUtil())->getCrmSettings($business_id)); $target = (int) ($settings['daily_call_target_per_agent'] ?? 50); $done = $todaySessions->whereNotNull('ended_at')->count(); return [ 'queue_remaining' => CrmCallQueue::where('business_id', $business_id) ->whereIn('status', ['available', 'locked']) ->whereHas('phoneFollowUp', function ($q) { $q->where('status', 'pending'); }) ->count(), 'today_calls' => $done, 'today_answered' => $todaySessions->where('outcome', 'answered')->count(), 'today_interested' => CrmPhoneFollowUp::where('business_id', $business_id)->where('assigned_to', $user_id)->where('status', 'interested')->whereDate('last_follow_up_at', $today)->count(), 'daily_target' => $target, 'target_progress' => $target > 0 ? min(100, round(($done / $target) * 100)) : 0, 'avg_lead_score' => round((float) CrmCallAssessment::whereHas('callSession', function ($q) use ($business_id, $user_id, $today) { $q->where('business_id', $business_id)->where('user_id', $user_id)->whereDate('started_at', $today); })->avg('cooperation_score') ?: 0, 1), ]; } protected function objectionOptions(): array { return [ 'price' => __('crm::lang.objection_price'), 'competitor' => __('crm::lang.objection_competitor'), 'timing' => __('crm::lang.objection_timing'), 'no_need' => __('crm::lang.objection_no_need'), 'no_budget' => __('crm::lang.objection_no_budget'), 'send_email' => __('crm::lang.objection_send_email'), ]; } public function releaseQueue(Request $request) { $this->authorizeAccess(); $released = $this->callQueueService->release((int) $request->input('queue_id'), auth()->id()); return response()->json([ 'success' => $released, 'msg' => $released ? __('crm::lang.queue_released') : __('messages.something_went_wrong'), ]); } public function acquireNext(Request $request) { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id'); $queue = $this->callQueueService->acquireNext( $business_id, auth()->id(), $request->input('campaign_id') ); if (empty($queue)) { return response()->json(['success' => false, 'msg' => __('crm::lang.no_numbers_in_queue')]); } return response()->json([ 'success' => true, 'queue' => $queue, 'phone' => $queue->phoneFollowUp, ]); } public function startSession(Request $request) { $this->authorizeAccess(); $session = $this->callQueueService->startSession((int) $request->input('queue_id'), auth()->id()); if (empty($session)) { return response()->json(['success' => false, 'msg' => __('messages.something_went_wrong')]); } return response()->json(['success' => true, 'session' => $session]); } public function workspaceData($phone_id) { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id'); $phone = CrmPhoneFollowUp::where('business_id', $business_id)->findOrFail($phone_id); $phoneListUtil = new PhoneListUtil(); $logs = $phone->logs()->with('createdBy')->limit(30)->get(); $callLogs = $phoneListUtil->getCallLogsForPhone($phone); $assessments = CrmCallAssessment::where('phone_follow_up_id', $phone->id)->with('assessedBy')->latest()->limit(10)->get(); $statuses = CrmPhoneFollowUp::statusDropdown(); $company = null; $suggestedFields = []; $contacts = []; if (! empty($phone->company_id)) { $company = CrmCompany::with(['contacts', 'branches', 'phones', 'requirements.product'])->find($phone->company_id); } if (empty($company)) { $company = $this->companyProfileService->findOrCreateForPhone($phone, auth()->id()); $company->load(['contacts', 'branches', 'phones', 'requirements']); } $suggestedFields = $this->companyProfileService->getSuggestedFieldsForCall($company); $contacts = $company->contacts; return response()->json([ 'phone' => $phone, 'statuses' => $statuses, 'logs' => $logs->map(function ($log) use ($statuses) { return [ 'status' => $statuses[$log->status] ?? $log->status, 'note' => $log->note, 'created_at' => $log->created_at?->format('Y-m-d H:i'), 'user' => $log->createdBy?->user_full_name, 'is_auto' => $log->is_auto, ]; }), 'call_logs' => $callLogs, 'assessments' => $assessments, 'company' => $company, 'suggested_fields' => $suggestedFields, 'contacts' => $contacts, 'company_url' => action([CompanyProfileController::class, 'show'], $company->id), ]); } public function completeSession(Request $request, $session_id) { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id') ?? auth()->user()->business_id; $request->validate([ 'outcome' => 'required|string', 'status' => 'nullable|string', 'note' => 'nullable|string', 'reception_score' => 'nullable|integer|min:1|max:5', 'tone_score' => 'nullable|integer|min:1|max:5', 'cooperation_score' => 'nullable|integer|min:1|max:5', ]); $result = $this->completionService->complete( (int) $session_id, auth()->id(), $business_id, $request->all() ); return response()->json($result); } public function previewOffers($company_id) { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id'); $company = CrmCompany::where('business_id', $business_id)->findOrFail($company_id); $matcher = new \Modules\Crm\Services\OfferMatchingService(); return response()->json(['success' => true, 'offers' => $matcher->matchForCompany($company)]); } public function sendOffers(Request $request) { $this->authorizeAccess(); $business_id = request()->session()->get('user.business_id'); $request->validate([ 'company_id' => 'required|integer', 'offer_ids' => 'required|array', ]); foreach ($request->input('offer_ids') as $offerId) { if (empty($offerId)) { continue; } CrmCompanyOffer::create([ 'company_id' => $request->input('company_id'), 'offer_catalog_id' => $offerId, 'call_session_id' => $request->input('call_session_id'), 'status' => 'draft', 'sent_via' => 'manual', 'sent_by' => auth()->id(), 'sent_at' => now(), ]); } return response()->json(['success' => true, 'msg' => __('crm::lang.offers_saved')]); } }