getVariable('CALLERID(num)'); \Log::info("Caller ID: {$num}"); $did = $agi->getFullVariable('CALLERID(dnid)'); \Log::info("CALLERID(dnid): {$did}"); $destination = $this->decideRoute($num, $did); \Log::info("Decided destination: {$destination}"); $agi->setVariable('NEXT_DEST', $destination); \Log::info("Dynamic Router: Caller {$num} → {$destination}"); } catch (\Throwable $e) { \Log::error('AgiDynamicRouter ERROR: ' . $e->getMessage()); } return 0; } /** * Resolve settings using the first company context (no auth in AGI). */ protected function getRoutingSettings(): array { $companyId = Company::value('id'); $method = (int) CompanySettings::get('call_routing_method', 2, $companyId); $defaultQueue = CompanySettings::get('call_default_queue', '700', $companyId) ?: '700'; return ['method' => $method, 'defaultQueue' => $defaultQueue]; } protected function decideRoute($num, $did) { $settings = $this->getRoutingSettings(); $method = $settings['method']; $defaultQueue = $settings['defaultQueue']; // $client = new \GuzzleHttp\Client(); // $response = $client->get('http://localhost/api/webform/getAvailAgent'); // $data = json_decode($response->getBody(), true); // $availableAgents = $this->getAvailableAgents($data); // ── Method 3: route by lead ownership ──────────────────────────── if ($method === 3) { $userId = $this->findLeadOwner($num); if ($userId !== null) { return 'ext-queues,7' . $userId . ',1'; } return 'ext-queues,' . $defaultQueue . ',1'; } // ── Methods 1 & 2: route by last answered agent ─────────────────── $query = DB::table('asteriskcdrdb.queuelog') ->select('queuelog.id', 'cdr.did', 'cdr.src', 'users.id as dst') ->join('asteriskcdrdb.cdr', 'cdr.uniqueid', '=', 'queuelog.callid') ->leftJoin('users', 'users.name', '=', 'queuelog.agent') ->whereIn('queuelog.event', ['COMPLETECALLER', 'COMPLETEAGENT']) ->where('cdr.src', $num) ->whereBetween('queuelog.time', [Carbon::now()->subHours(12), Carbon::now()]) ->where('cdr.disposition', 'ANSWERED'); // Method 2 additionally requires the same DID if ($method === 2) { $query->where('cdr.did', $did); } $dst = $query->orderBy('queuelog.time', 'DESC')->first(); if ($dst) { foreach ($availableAgents as $agent) { if ((int) $agent['extension'] === (int) $dst->dst) { \Log::info("AgiDynamicRouter method {$method}: routing to agent {$dst->dst}"); return 'ext-queues,7' . $dst->dst . ',1'; } } } return 'ext-queues,' . $defaultQueue . ',1'; } /** * Return only available agents from the API response. */ protected function getAvailableAgents(array $data): array { if (empty($data['agents'])) { return []; } return array_values(array_filter($data['agents'], function ($agent) { return isset($agent['status']['status']) && $agent['status']['status'] === 'Avail'; })); } /** * Search leads table for the caller number and return the owning user ID, * or null if no matching lead is found. */ protected function findLeadOwner(string $num): ?int { // Normalise to last 11 digits for flexible matching $short = strlen($num) > 11 ? substr($num, -11) : $num; $lead = Lead::where(function ($q) use ($num, $short) { $q->where('phone', 'LIKE', "%{$num}%") ->orWhere('mobile', 'LIKE', "%{$num}%") ->orWhere('phone', 'LIKE', "%{$short}%") ->orWhere('mobile', 'LIKE', "%{$short}%") ->orWhere('phone', 'LIKE', "%0{$short}%") ->orWhere('mobile', 'LIKE', "%0{$short}%") ->orWhere('phone', 'LIKE', "%2{$short}%") ->orWhere('mobile', 'LIKE', "%2{$short}%") ->orWhere('phone', 'LIKE', "%+2{$short}%") ->orWhere('mobile', 'LIKE', "%+2{$short}%"); }) ->where('owned_by_type', 'Modules\Platform\User\Entities\User') ->whereNotNull('owned_by_id') ->orderByDesc('updated_at') ->first(['owned_by_id']); return $lead ? (int) $lead->owned_by_id : null; } }