mirror of https://github.com/Lukibeg/OmniBoard.git
fix: Status de agentes V0.1.
fix: Status de agentes V0.1.
This commit is contained in:
commit
31fa9a00e8
|
|
@ -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'
|
// Tenta achar a interface. Se for MemberStatus, vem em 'Interface'. Se for AgentConnect, vem em 'Interface' ou 'MemberName'
|
||||||
$interface = $data['Interface'] ?? $data['MemberName'] ?? null;
|
$interface = $data['Interface'] ?? $data['MemberName'] ?? null;
|
||||||
|
|
||||||
// Auto-discovery de Filas e Agentes
|
// 1. Auto-discovery (Com proteção para não salvar a fila fake do Auto-Hangup)
|
||||||
if ($queueNumber) {
|
if ($queueNumber && $queueNumber !== 'Auto-Hangup') {
|
||||||
$this->saveQueues($queueNumber, $tenant);
|
$this->saveQueues($queueNumber, $tenant);
|
||||||
}
|
}
|
||||||
if ($interface) {
|
if ($interface) {
|
||||||
|
|
@ -42,7 +42,19 @@ public function handle(Request $request)
|
||||||
return response()->json(['status' => 'ignored']);
|
return response()->json(['status' => 'ignored']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera Fila
|
// 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)
|
||||||
$queue = Queue::where('tenant_id', $tenant->id)
|
$queue = Queue::where('tenant_id', $tenant->id)
|
||||||
->where('source_id', $queueNumber)
|
->where('source_id', $queueNumber)
|
||||||
->first();
|
->first();
|
||||||
|
|
@ -51,21 +63,16 @@ public function handle(Request $request)
|
||||||
return response()->json(['error' => 'Fila não encontrada'], 404);
|
return response()->json(['error' => 'Fila não encontrada'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$agent = $this->findAgent($tenant->id, $data);
|
|
||||||
|
|
||||||
|
|
||||||
switch ($eventName) {
|
switch ($eventName) {
|
||||||
case 'QueueCallerJoin':
|
case 'QueueCallerJoin':
|
||||||
$this->handleJoin($queue, $data);
|
$this->handleJoin($queue, $data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'AgentConnect':
|
case 'AgentConnect':
|
||||||
// Foco: Mudar para 'talking' e atualizar métricas
|
|
||||||
$this->handleConnect($queue, $data);
|
$this->handleConnect($queue, $data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'AgentComplete':
|
case 'AgentComplete':
|
||||||
// Foco: Encerrar contagem de tempo de fala
|
|
||||||
$this->handleComplete($queue, $data);
|
$this->handleComplete($queue, $data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -74,7 +81,6 @@ public function handle(Request $request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'QueueMemberPause':
|
case 'QueueMemberPause':
|
||||||
// Evento explícito de pausa (Alguém clicou no botão de pausa)
|
|
||||||
if ($agent) $this->handlePause($agent, $data, $tenant->id);
|
if ($agent) $this->handlePause($agent, $data, $tenant->id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -83,7 +89,6 @@ public function handle(Request $request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'QueueMemberStatus':
|
case 'QueueMemberStatus':
|
||||||
// Foco: Atualizar Presença (Offline, Disponível, Pausado, Busy)
|
|
||||||
if ($agent) $this->handleMemberStatus($agent, $data, $tenant->id);
|
if ($agent) $this->handleMemberStatus($agent, $data, $tenant->id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -95,6 +100,20 @@ public function handle(Request $request)
|
||||||
// HANDLERS
|
// 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)
|
private function handleMemberStatus($agent, $data, $tenantId)
|
||||||
{
|
{
|
||||||
$isPaused = ($data['Paused'] ?? '0') == '1';
|
$isPaused = ($data['Paused'] ?? '0') == '1';
|
||||||
|
|
@ -126,7 +145,6 @@ private function handleMemberStatus($agent, $data, $tenantId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRAVA DE IDEMPOTÊNCIA (Igual ao handlePause)
|
|
||||||
if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
|
if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -141,12 +159,10 @@ private function handleMemberStatus($agent, $data, $tenantId)
|
||||||
|
|
||||||
private function handleConnect($queue, $data)
|
private function handleConnect($queue, $data)
|
||||||
{
|
{
|
||||||
// 1. Remove da Lista de Espera
|
|
||||||
WaitingList::where('queue_id', $queue->id)
|
WaitingList::where('queue_id', $queue->id)
|
||||||
->where('caller_number', $data['CallerIDNum'])
|
->where('caller_number', $data['CallerIDNum'])
|
||||||
->delete();
|
->delete();
|
||||||
|
|
||||||
// 2. Atualiza Métricas da Fila
|
|
||||||
$metric = $this->getTodayMetric($queue);
|
$metric = $this->getTodayMetric($queue);
|
||||||
$holdTime = intval($data['HoldTime'] ?? 0);
|
$holdTime = intval($data['HoldTime'] ?? 0);
|
||||||
$newAvg = (($metric->avg_wait_time * $metric->answered_count) + $holdTime) / ($metric->answered_count + 1);
|
$newAvg = (($metric->avg_wait_time * $metric->answered_count) + $holdTime) / ($metric->answered_count + 1);
|
||||||
|
|
@ -155,7 +171,6 @@ private function handleConnect($queue, $data)
|
||||||
$metric->answered_count += 1;
|
$metric->answered_count += 1;
|
||||||
$metric->save();
|
$metric->save();
|
||||||
|
|
||||||
// 3. Atualiza Agente para Talking (Feedback Visual Imediato)
|
|
||||||
$agent = $this->findAgent($queue->tenant_id, $data);
|
$agent = $this->findAgent($queue->tenant_id, $data);
|
||||||
if ($agent) {
|
if ($agent) {
|
||||||
$agent->status = 'talking';
|
$agent->status = 'talking';
|
||||||
|
|
@ -169,7 +184,6 @@ private function handleConnect($queue, $data)
|
||||||
|
|
||||||
private function handleComplete($queue, $data)
|
private function handleComplete($queue, $data)
|
||||||
{
|
{
|
||||||
// Atualiza tempo médio falado
|
|
||||||
$talkTime = intval($data['TalkTime'] ?? 0);
|
$talkTime = intval($data['TalkTime'] ?? 0);
|
||||||
$metric = $this->getTodayMetric($queue);
|
$metric = $this->getTodayMetric($queue);
|
||||||
|
|
||||||
|
|
@ -179,17 +193,13 @@ private function handleComplete($queue, $data)
|
||||||
$metric->save();
|
$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);
|
$this->broadcastUpdate($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handlePause($agent, $data, $tenantId)
|
private function handlePause($agent, $data, $tenantId)
|
||||||
{
|
{
|
||||||
$isPaused = isset($data['Paused']) && $data['Paused'] == '1';
|
$isPaused = isset($data['Paused']) && $data['Paused'] == '1';
|
||||||
$targetStatus = $isPaused ? 'paused' : 'available'; // Se despausar, assume livre
|
$targetStatus = $isPaused ? 'paused' : 'available';
|
||||||
|
|
||||||
$targetReason = null;
|
$targetReason = null;
|
||||||
if ($isPaused) {
|
if ($isPaused) {
|
||||||
|
|
@ -197,9 +207,6 @@ private function handlePause($agent, $data, $tenantId)
|
||||||
if (trim($targetReason) === '') $targetReason = 'Pausa';
|
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) {
|
if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -248,13 +255,11 @@ private function handleJoin($queue, $data)
|
||||||
|
|
||||||
private function saveAgent($interface, $tenant)
|
private function saveAgent($interface, $tenant)
|
||||||
{
|
{
|
||||||
|
|
||||||
$exists = Agent::where('tenant_id', $tenant->id)
|
$exists = Agent::where('tenant_id', $tenant->id)
|
||||||
->where('interface', $interface)
|
->where('interface', $interface)
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if (!$exists) {
|
if (!$exists) {
|
||||||
// Lógica de extração de nome
|
|
||||||
$name = $interface;
|
$name = $interface;
|
||||||
if (strpos($interface, '/') !== false) {
|
if (strpos($interface, '/') !== false) {
|
||||||
$parts = explode('/', $interface);
|
$parts = explode('/', $interface);
|
||||||
|
|
@ -272,6 +277,9 @@ private function saveAgent($interface, $tenant)
|
||||||
|
|
||||||
private function saveQueues($queueSourceId, $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)
|
$exists = Queue::where('tenant_id', $tenant->id)
|
||||||
->where('source_id', $queueSourceId)
|
->where('source_id', $queueSourceId)
|
||||||
->exists();
|
->exists();
|
||||||
|
|
@ -291,7 +299,6 @@ private function findAgent($tenantId, $data)
|
||||||
{
|
{
|
||||||
$interface = $data['Interface'] ?? $data['MemberName'] ?? null;
|
$interface = $data['Interface'] ?? $data['MemberName'] ?? null;
|
||||||
|
|
||||||
|
|
||||||
return Agent::where('tenant_id', $tenantId)
|
return Agent::where('tenant_id', $tenantId)
|
||||||
->where('interface', $interface)
|
->where('interface', $interface)
|
||||||
->first();
|
->first();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue