mirror of https://github.com/Lukibeg/OmniBoard.git
Compare commits
No commits in common. "31fa9a00e804ae625b892797599a4dcc7b67dbaa" and "67b35bdf3ed12150cc390fe5c8774e97d370eac6" have entirely different histories.
31fa9a00e8
...
67b35bdf3e
|
|
@ -30,8 +30,8 @@ public function handle(Request $request)
|
|||
// Tenta achar a interface. Se for MemberStatus, vem em 'Interface'. Se for AgentConnect, vem em 'Interface' ou 'MemberName'
|
||||
$interface = $data['Interface'] ?? $data['MemberName'] ?? null;
|
||||
|
||||
// 1. Auto-discovery (Com proteção para não salvar a fila fake do Auto-Hangup)
|
||||
if ($queueNumber && $queueNumber !== 'Auto-Hangup') {
|
||||
// Auto-discovery de Filas e Agentes
|
||||
if ($queueNumber) {
|
||||
$this->saveQueues($queueNumber, $tenant);
|
||||
}
|
||||
if ($interface) {
|
||||
|
|
@ -42,19 +42,7 @@ public function handle(Request $request)
|
|||
return response()->json(['status' => 'ignored']);
|
||||
}
|
||||
|
||||
// 2. Busca o Agente (Movi para cima, pois precisamos dele para o AgentFinished)
|
||||
$agent = $this->findAgent($tenant->id, $data);
|
||||
|
||||
// 3. INTERCEPTADOR ANTI-FANTASMA
|
||||
// Processa o AgentFinished ANTES de validar a fila, pois 'Auto-Hangup' não existe no BD
|
||||
if ($eventName === 'AgentFinished') {
|
||||
if ($agent) {
|
||||
$this->handleFinished($agent, $tenant->id);
|
||||
}
|
||||
return response()->json(['status' => 'fixed']);
|
||||
}
|
||||
|
||||
// 4. Recupera Fila (Fluxo normal)
|
||||
// Recupera Fila
|
||||
$queue = Queue::where('tenant_id', $tenant->id)
|
||||
->where('source_id', $queueNumber)
|
||||
->first();
|
||||
|
|
@ -63,16 +51,21 @@ public function handle(Request $request)
|
|||
return response()->json(['error' => 'Fila não encontrada'], 404);
|
||||
}
|
||||
|
||||
$agent = $this->findAgent($tenant->id, $data);
|
||||
|
||||
|
||||
switch ($eventName) {
|
||||
case 'QueueCallerJoin':
|
||||
$this->handleJoin($queue, $data);
|
||||
break;
|
||||
|
||||
case 'AgentConnect':
|
||||
// Foco: Mudar para 'talking' e atualizar métricas
|
||||
$this->handleConnect($queue, $data);
|
||||
break;
|
||||
|
||||
case 'AgentComplete':
|
||||
// Foco: Encerrar contagem de tempo de fala
|
||||
$this->handleComplete($queue, $data);
|
||||
break;
|
||||
|
||||
|
|
@ -81,6 +74,7 @@ public function handle(Request $request)
|
|||
break;
|
||||
|
||||
case 'QueueMemberPause':
|
||||
// Evento explícito de pausa (Alguém clicou no botão de pausa)
|
||||
if ($agent) $this->handlePause($agent, $data, $tenant->id);
|
||||
break;
|
||||
|
||||
|
|
@ -89,6 +83,7 @@ public function handle(Request $request)
|
|||
break;
|
||||
|
||||
case 'QueueMemberStatus':
|
||||
// Foco: Atualizar Presença (Offline, Disponível, Pausado, Busy)
|
||||
if ($agent) $this->handleMemberStatus($agent, $data, $tenant->id);
|
||||
break;
|
||||
}
|
||||
|
|
@ -100,20 +95,6 @@ public function handle(Request $request)
|
|||
// HANDLERS
|
||||
// =========================================================================
|
||||
|
||||
// --- NOVO HANDLER: Solução para Agentes Fantasmas ---
|
||||
private function handleFinished($agent, $tenantId)
|
||||
{
|
||||
// Só forçamos 'available' se ele estiver 'talking'.
|
||||
// Se ele estiver 'paused', não mexemos (para respeitar pausas feitas durante chamada)
|
||||
if ($agent->status === 'talking') {
|
||||
$agent->status = 'available';
|
||||
$agent->last_status_change = now();
|
||||
$agent->save();
|
||||
|
||||
broadcast(new DashboardUpdate($tenantId));
|
||||
}
|
||||
}
|
||||
|
||||
private function handleMemberStatus($agent, $data, $tenantId)
|
||||
{
|
||||
$isPaused = ($data['Paused'] ?? '0') == '1';
|
||||
|
|
@ -145,6 +126,7 @@ private function handleMemberStatus($agent, $data, $tenantId)
|
|||
}
|
||||
}
|
||||
|
||||
// TRAVA DE IDEMPOTÊNCIA (Igual ao handlePause)
|
||||
if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -159,10 +141,12 @@ private function handleMemberStatus($agent, $data, $tenantId)
|
|||
|
||||
private function handleConnect($queue, $data)
|
||||
{
|
||||
// 1. Remove da Lista de Espera
|
||||
WaitingList::where('queue_id', $queue->id)
|
||||
->where('caller_number', $data['CallerIDNum'])
|
||||
->delete();
|
||||
|
||||
// 2. Atualiza Métricas da Fila
|
||||
$metric = $this->getTodayMetric($queue);
|
||||
$holdTime = intval($data['HoldTime'] ?? 0);
|
||||
$newAvg = (($metric->avg_wait_time * $metric->answered_count) + $holdTime) / ($metric->answered_count + 1);
|
||||
|
|
@ -171,6 +155,7 @@ private function handleConnect($queue, $data)
|
|||
$metric->answered_count += 1;
|
||||
$metric->save();
|
||||
|
||||
// 3. Atualiza Agente para Talking (Feedback Visual Imediato)
|
||||
$agent = $this->findAgent($queue->tenant_id, $data);
|
||||
if ($agent) {
|
||||
$agent->status = 'talking';
|
||||
|
|
@ -184,6 +169,7 @@ private function handleConnect($queue, $data)
|
|||
|
||||
private function handleComplete($queue, $data)
|
||||
{
|
||||
// Atualiza tempo médio falado
|
||||
$talkTime = intval($data['TalkTime'] ?? 0);
|
||||
$metric = $this->getTodayMetric($queue);
|
||||
|
||||
|
|
@ -193,13 +179,17 @@ private function handleComplete($queue, $data)
|
|||
$metric->save();
|
||||
}
|
||||
|
||||
// NOTA: Removemos a lógica de mudar status para 'available' aqui.
|
||||
// Deixamos o 'QueueMemberStatus' cuidar disso quando o telefone for colocado no gancho.
|
||||
// Isso evita conflitos se o agente desligar e imediatamente receber outra chamada.
|
||||
|
||||
$this->broadcastUpdate($queue);
|
||||
}
|
||||
|
||||
private function handlePause($agent, $data, $tenantId)
|
||||
{
|
||||
$isPaused = isset($data['Paused']) && $data['Paused'] == '1';
|
||||
$targetStatus = $isPaused ? 'paused' : 'available';
|
||||
$targetStatus = $isPaused ? 'paused' : 'available'; // Se despausar, assume livre
|
||||
|
||||
$targetReason = null;
|
||||
if ($isPaused) {
|
||||
|
|
@ -207,6 +197,9 @@ private function handlePause($agent, $data, $tenantId)
|
|||
if (trim($targetReason) === '') $targetReason = 'Pausa';
|
||||
}
|
||||
|
||||
// --- TRAVA DE IDEMPOTÊNCIA ---
|
||||
// Se o agente está em 10 filas, esse evento dispara 10 vezes.
|
||||
// Se o status já for igual, IGNORA para não spamar o WebSocket.
|
||||
if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -255,11 +248,13 @@ private function handleJoin($queue, $data)
|
|||
|
||||
private function saveAgent($interface, $tenant)
|
||||
{
|
||||
|
||||
$exists = Agent::where('tenant_id', $tenant->id)
|
||||
->where('interface', $interface)
|
||||
->exists();
|
||||
|
||||
if (!$exists) {
|
||||
// Lógica de extração de nome
|
||||
$name = $interface;
|
||||
if (strpos($interface, '/') !== false) {
|
||||
$parts = explode('/', $interface);
|
||||
|
|
@ -277,9 +272,6 @@ private function saveAgent($interface, $tenant)
|
|||
|
||||
private function saveQueues($queueSourceId, $tenant)
|
||||
{
|
||||
// Proteção extra para não criar fila suja
|
||||
if ($queueSourceId === 'Auto-Hangup') return;
|
||||
|
||||
$exists = Queue::where('tenant_id', $tenant->id)
|
||||
->where('source_id', $queueSourceId)
|
||||
->exists();
|
||||
|
|
@ -299,6 +291,7 @@ private function findAgent($tenantId, $data)
|
|||
{
|
||||
$interface = $data['Interface'] ?? $data['MemberName'] ?? null;
|
||||
|
||||
|
||||
return Agent::where('tenant_id', $tenantId)
|
||||
->where('interface', $interface)
|
||||
->first();
|
||||
|
|
|
|||
Loading…
Reference in New Issue