getAgi(); $client->answer(); } public function log($msg){ $agi = $this->getAgi(); $this->logger->debug($msg); $agi->consoleLog($msg); } public function shutdown(){ return true; } /** * Read the configured number of survey questions (1–5). * Called inside AGI — no Auth context, so we use raw \Settings. */ private function getQuestionsCount(): int { $val = \Settings::get('SURVEY_QUESTIONS_COUNT'); $count = $val ? (int) $val : 1; return max(1, min(5, $count)); } private function getAnswerMaxDigits(): int { $val = \Settings::get('SURVEY_ANSWER_MAX_DIGITS'); $count = $val ? (int) $val : 1; return max(1, min(10, $count)); } private function getFirstDigitTimeoutSeconds(): int { $val = \Settings::get('SURVEY_FIRST_DIGIT_TIMEOUT_SECONDS'); $seconds = $val ? (int) $val : 10; return max(1, min(60, $seconds)); } private function getInterDigitTimeoutSeconds(): int { $val = \Settings::get('SURVEY_INTER_DIGIT_TIMEOUT_SECONDS'); $seconds = $val ? (int) $val : 1; return max(1, min(60, $seconds)); } public function run(){ $client = $this->getAgi(); $uniqueid = $client->getVariable('UNIQUEID'); $linkedid = $client->getVariable('SurveyLinkedId'); if (!$linkedid) { $linkedid = $client->getFullVariable('CHANNEL(LINKEDID)'); } // Asterisk returns false when a variable is unset; normalise before logging/storing. $linkedid = is_string($linkedid) ? $linkedid : ''; $leadId = $client->getVariable('LeadId'); $campaignId = $client->getVariable('CampaignID'); $isSurveyDial = $client->getVariable('IsSurveyDial'); // Queue-name based detection shared with the GLN AGI; Arabic by default. $language = $this->isMultiLanguageEnabled() ? $this->resolveCallLanguage($client) : CallLanguageResolver::arabicOnlySelection(); $questionsCount = $this->getQuestionsCount(); $answerMaxDigits = $this->getAnswerMaxDigits(); $firstDigitTimeoutSeconds = $this->getFirstDigitTimeoutSeconds(); $interDigitTimeoutSeconds = $this->getInterDigitTimeoutSeconds(); $audioFiles = AgiPromptPaths::surveyPromptsForLanguage($language['language']); $thanksPrompt = AgiPromptPaths::surveyThanksPromptForLanguage($language['language']); \Log::info('Survey language resolved', [ 'linkedid' => $linkedid, 'queue_number' => $language['queue_number'], 'queue_name' => $language['queue_name'], 'current_queue_number' => $language['current_queue_number'], 'language' => $language['language'], 'language_source' => $language['language_source'], 'thank_you_prompt' => $thanksPrompt, ]); $answers = []; for ($q = 1; $q <= $questionsCount; $q++) { try { $prompt = $audioFiles[$q]; \Log::info("Playing question {$q}: " . $prompt); $result = $client->getData($prompt, (string) ($firstDigitTimeoutSeconds * 1000), 1); $digit = $result->isTimeout() ? '' : $result->getDigits(); $digit = is_string($digit) ? $digit : ''; // Collect optional extra digits; one digit is valid and is submitted after this short pause. while ($digit !== '' && strlen($digit) < $answerMaxDigits) { $nextDigitResult = $client->waitDigit($interDigitTimeoutSeconds * 1000); $nextDigit = $nextDigitResult->getDigits(); if (!is_string($nextDigit) || !ctype_digit($nextDigit)) { break; } $digit .= $nextDigit; } $answers[$q] = ($digit !== '') ? $digit : 'No Input'; \Log::info("Question {$q} answer: " . $answers[$q]); } catch (\Exception $e) { break; } } \DB::table('surveys')->insert([ 'linkedid' => $linkedid ?: '', 'uniqueid' => $uniqueid, 'customer_choice' => $answers[1] ?? 'No Input', // q1 — backward compat 'q2' => $answers[2] ?? null, 'q3' => $answers[3] ?? null, 'q4' => $answers[4] ?? null, 'q5' => $answers[5] ?? null, 'lead_id' => $leadId ?: null, 'campaign_id' => $campaignId ?: null, 'is_dialer' => $isSurveyDial ? 1 : 0, 'created_at' => now(), 'updated_at' => now(), ]); if ($linkedid) { $updatedCallLogs = CallLogSyncService::refreshSurvey($linkedid); \Log::info('Survey answers synced to call logs', [ 'linkedid' => $linkedid, 'updated_call_logs' => $updatedCallLogs, ]); } \Log::debug(['surveyAnswers' => $answers]); $playThanksPrompt = \Settings::get('SURVEY_PLAY_THANKS_PROMPT'); if ($playThanksPrompt === null || filter_var($playThanksPrompt, FILTER_VALIDATE_BOOLEAN)) { $client->streamFile($thanksPrompt); } return true; } /** * @return array{queue_number: ?string, queue_name: ?string, current_queue_number: ?string, language: string, language_source: string} */ protected function resolveCallLanguage(IClient $client): array { return (new CallLanguageResolver())->resolve($client, $this->isMultiLanguageEnabled()); } protected function isMultiLanguageEnabled(): bool { if ($this->multiLanguageEnabled === null) { $companyId = Company::value('id'); $this->multiLanguageEnabled = $companyId ? (bool) CompanySettings::get( SettingsHelper::S_COMPANY_GLN_MULTI_LANGUAGE_ENABLED, false, $companyId ) : false; } return $this->multiLanguageEnabled; } public function errorHandler($type, $message, $file, $line){ $this->log( 'ErrorHandler: ' . implode(' ', array($type, $message, $file, $line)) ); } public function signalHandler($signal){ $this->log('SignalHandler got signal: ' . $signal); $this->shutdown(); exit(0); } }