select([ 'uniqueid', 'linkedid', 'did', 'src', 'dstchannel', 'dcontext', 'lastapp', 'disposition', 'calldate', 'duration', 'billsec', ]) ->where('linkedid', $linkedid) ->orderBy('calldate', 'asc') ->get(); if ($cdrRows->isEmpty()) { if (CompanySettings::get(SettingsHelper::S_COMPANY_CONSOLE_DEBUG_LOGS)) { Log::warning("[DirectCallsService] No CDR rows for {$linkedid}"); } return false; } // ── Single pass: classify the call path ─────────────────────── $isQueueCall = false; $directLegs = []; $rootCdr = null; $answeredAny = false; foreach ($cdrRows as $leg) { if ($leg->uniqueid === $leg->linkedid) { $rootCdr = $rootCdr ?? $leg; } // Queue call path — handled by the existing queue pipeline. if ($leg->dcontext === self::QUEUE_DCONTEXT && $leg->lastapp === self::QUEUE_LASTAPP) { $isQueueCall = true; } // Direct call path — this leg dialed the extension directly. if ($leg->lastapp === self::DIRECT_LASTAPP && in_array($leg->dcontext, self::DIRECT_CONTEXTS, true)) { $directLegs[] = $leg; } if ($leg->disposition === 'ANSWERED') { $answeredAny = true; } } if ($isQueueCall) { if (CompanySettings::get(SettingsHelper::S_COMPANY_CONSOLE_DEBUG_LOGS)) { Log::info("[DirectCallsService] {$linkedid} is a queue call (dcontext=ext-queues, lastapp=Queue) — skipping."); } return false; } if (empty($directLegs)) { if (CompanySettings::get(SettingsHelper::S_COMPANY_CONSOLE_DEBUG_LOGS)) { Log::info("[DirectCallsService] {$linkedid} has no direct Dial leg (dcontext in " . implode('/', self::DIRECT_CONTEXTS) . ", lastapp=Dial) — skipping."); } return false; } $answered = $answeredAny; // ── Single pass: inbound metrics ────────────────────────────── // Ringtime sums every dial segment; talktime sums answered ones // (same aggregation as the queue pipeline over queuelog events). $ringtime = 0; $talktime = 0; foreach ($directLegs as $leg) { $duration = max(0, (int) $leg->duration); $billsec = max(0, (int) $leg->billsec); $ringtime += max(0, $duration - $billsec); if ($answered && $leg->disposition === 'ANSWERED') { $talktime += $billsec; } } // Target leg: first answered direct leg, else the first direct leg. $targetLeg = null; foreach ($directLegs as $leg) { if ($answered && $leg->disposition !== 'ANSWERED') { continue; } $targetLeg = $leg; break; } $targetLeg = $targetLeg ?? $directLegs[0]; $rootLeg = $rootCdr ?? $cdrRows->first(); $callerNumber = $rootLeg->src ?? null; if ($callerNumber !== null && str_starts_with($callerNumber, '+2')) { $callerNumber = substr($callerNumber, 2); } $userId = null; $dstchannel = $targetLeg->dstchannel ?? null; if ($dstchannel && preg_match('/\d+/', $dstchannel, $m)) { $userId = (int) $m[0]; } // Resolve the agent name from the extension inside the channel // string (e.g. PJSIP/997-00000020 -> 997 -> user name); never store // the full PJSIP channel as the agent identifier. $agent = 'NONE'; if ($userId !== null) { $agent = DB::table('users')->where('id', $userId)->value('name') ?? (string) $userId; } $callTime = $targetLeg->calldate; $reportDate = \Carbon\Carbon::parse($callTime)->format('Y-m-d'); $disposition = (string) $rootLeg->disposition; // ── Write ───────────────────────────────────────────────────── InboundReport::where('linkedid', $linkedid)->delete(); $report = InboundReport::create([ 'linkedid' => $linkedid, 'callid' => $targetLeg->uniqueid, 'call_time' => $callTime, 'queue_description' => 'Marketing Group', 'agent' => $agent, 'hangup_type' => $answered ? 'COMPLETECALLER' : $disposition, 'status' => $answered ? null : $disposition, 'ringtime' => $ringtime, 'talktime' => $talktime, 'caller_number' => $callerNumber, 'did' => $rootLeg->did ?? null, 'transfers_count' => max(0, count($directLegs) - 1), 'survey' => null, 'user_id' => $userId, 'enter_queuename' => 700, 'event' => $answered ? 'COMPLETECALLER' : $disposition, 'data5' => null, 'call_status' => $answered ? 'answered' : 'missed', 'report_date' => $reportDate, ]); CallLogSyncService::sync($linkedid, $answered ? 'inbound' : 'missed', [ 'phone_number' => $callerNumber, 'call_date' => $callTime, 'duration' => $ringtime + $talktime, 'talktime' => $talktime, 'ringtime' => $ringtime, 'user_id' => $userId, 'queue' => null, ]); return $report; } catch (\Exception $e) { if (CompanySettings::get(SettingsHelper::S_COMPANY_CONSOLE_DEBUG_LOGS)) { Log::error("[DirectCallsService] Error processing single direct call [{$linkedid}]: " . $e->getMessage()); } return false; } } }