From ac179cec9882988b4d80ad3adf7f9970c47fad69 Mon Sep 17 00:00:00 2001 From: lizandrogd <77708265+lizandrogd@users.noreply.github.com> Date: Wed, 21 Jan 2026 16:32:40 -0500 Subject: [PATCH] up --- api/attend.php | 41 +++++++++++++++++++++ api/get_conversations.php | 10 +++++- conversations.php | 41 ++++++++++++++++++++- scripts/add_user_in_service_column.php | 50 ++++++++++++++++++++++++++ services/BotService.php | 43 +++++++++++++++++++++- 5 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 api/attend.php create mode 100644 scripts/add_user_in_service_column.php diff --git a/api/attend.php b/api/attend.php new file mode 100644 index 0000000..59c5354 --- /dev/null +++ b/api/attend.php @@ -0,0 +1,41 @@ + false, 'error' => 'user_id required']); + exit; + } + + $db = Database::getInstance(); + $user = $db->fetch('SELECT phone_number FROM users WHERE id = :id', ['id' => $userId]); + if (!$user) { + http_response_code(404); + echo json_encode(['success' => false, 'error' => 'User not found']); + exit; + } + + $operator = $_SESSION['admin_user'] ?? null; + $operatorId = $operator['id'] ?? null; + + try { + require_once __DIR__ . '/../services/BotService.php'; + $bot = new BotService(); + $bot->attendConversation($user['phone_number'], $operatorId); + echo json_encode(['success' => true]); + } catch (Exception $e) { + // Fallback: apply updates directly and log activity + $now = date('Y-m-d H:i:s'); + $db->update('users', ['in_service' => 1, 'in_service_by' => $operatorId, 'in_service_at' => $now, 'advisor_requested' => 0], 'id = :id', ['id' => $userId]); + $db->insert('operator_activity', ['user_id' => $userId, 'operator_id' => $operatorId, 'action' => 'attend', 'details' => 'Marked in_service via fallback', 'created_at' => $now]); + echo json_encode(['success' => true, 'warning' => 'BotService failed, fallback applied']); + } +} catch (Exception $e) { + http_response_code(500); + echo json_encode(['success' => false, 'error' => $e->getMessage()]); +} diff --git a/api/get_conversations.php b/api/get_conversations.php index fd8365f..d811d9b 100644 --- a/api/get_conversations.php +++ b/api/get_conversations.php @@ -23,6 +23,10 @@ try { u.avatar_url, u.bot_enabled, u.on_hold, + u.advisor_requested, + u.in_service, + u.in_service_by, + u.in_service_at, lm.message_id AS last_message_id, lm.content AS last_message, lm.direction AS direction, @@ -60,7 +64,11 @@ try { 'message_type' => $conv['message_type'] ?? 'text', 'unread_count' => intval($conv['unread_count'] ?? 0), 'bot_enabled' => isset($conv['bot_enabled']) ? (bool)$conv['bot_enabled'] : true, - 'on_hold' => isset($conv['on_hold']) ? (bool)$conv['on_hold'] : false + 'on_hold' => isset($conv['on_hold']) ? (bool)$conv['on_hold'] : false, + 'advisor_requested' => isset($conv['advisor_requested']) ? (bool)$conv['advisor_requested'] : false, + 'in_service' => isset($conv['in_service']) ? (bool)$conv['in_service'] : false, + 'in_service_by' => isset($conv['in_service_by']) ? intval($conv['in_service_by']) : null, + 'in_service_at' => $conv['in_service_at'] ?? null ]; }, $conversations); diff --git a/conversations.php b/conversations.php index 4db4910..3bcf613 100644 --- a/conversations.php +++ b/conversations.php @@ -475,7 +475,10 @@ +1234567890 -
+
+ + +
@@ -886,6 +889,42 @@ alert('Error liberando espera'); } }; + + // Attender (marcar 'en servicio' sin liberar) + const attendBtn = document.getElementById('attend-btn'); + if (attendBtn) { + attendBtn.style.display = (conv.advisor_requested && !conv.in_service) ? 'inline-block' : 'none'; + attendBtn.onclick = async () => { + try { + const resp = await fetch('api/attend.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ user_id: userId }) + }); + if (resp.status === 401) { + alert('Sesi贸n expirada. Por favor inicie sesi贸n de nuevo.'); + return; + } + const json = await resp.json(); + if (json && json.success) { + conv.in_service = true; + conv.advisor_requested = 0; + holdIndicator.textContent = 'EN SERVICIO'; + holdIndicator.style.color = '#28a745'; + holdIndicator.style.display = 'inline'; + attendBtn.style.display = 'none'; + // keep release available + releaseBtn.style.display = 'inline-block'; + await this.loadConversations(); + } else { + alert('Error al marcar como atendida'); + } + } catch (e) { + console.error('Error attending', e); + alert('Error al atender'); + } + }; + } } } }; diff --git a/scripts/add_user_in_service_column.php b/scripts/add_user_in_service_column.php new file mode 100644 index 0000000..efb1732 --- /dev/null +++ b/scripts/add_user_in_service_column.php @@ -0,0 +1,50 @@ +fetch("SHOW COLUMNS FROM users LIKE 'in_service'"); + if ($col) { + echo "Column in_service already exists\n"; + } else { + $db->query("ALTER TABLE users ADD COLUMN in_service TINYINT(1) DEFAULT 0 AFTER advisor_requested"); + echo "Added in_service column\n"; + } + + $col = $db->fetch("SHOW COLUMNS FROM users LIKE 'in_service_by'"); + if ($col) { + echo "Column in_service_by already exists\n"; + } else { + $db->query("ALTER TABLE users ADD COLUMN in_service_by INT NULL AFTER in_service"); + echo "Added in_service_by column\n"; + } + + $col = $db->fetch("SHOW COLUMNS FROM users LIKE 'in_service_at'"); + if ($col) { + echo "Column in_service_at already exists\n"; + } else { + $db->query("ALTER TABLE users ADD COLUMN in_service_at DATETIME NULL AFTER in_service_by"); + echo "Added in_service_at column\n"; + } + + // Crear tabla operator_activity si no existe + $check = $db->fetch("SHOW TABLES LIKE 'operator_activity'"); + if ($check) { + echo "Table operator_activity already exists\n"; + } else { + $sql = "CREATE TABLE operator_activity ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NULL, + operator_id INT NULL, + action VARCHAR(50) NOT NULL, + details TEXT NULL, + created_at DATETIME NOT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"; + $db->query($sql); + echo "Created table operator_activity\n"; + } + + echo "Done.\n"; +} catch (Exception $e) { + echo "Migration failed: " . $e->getMessage() . "\n"; +} diff --git a/services/BotService.php b/services/BotService.php index 0c1bac4..a1ed429 100644 --- a/services/BotService.php +++ b/services/BotService.php @@ -138,7 +138,7 @@ class BotService { } else { // Opcional: informar que el asesor ya respondi贸 y no podemos enviar autom谩ticas try { - $this->whatsappService->sendTextMessage($phoneNumber, "馃敃 Un asesor ya ha intervenido en la conversaci贸n, por favor espera su respuesta o utiliza *menu* para ver opciones."); + //$this->whatsappService->sendTextMessage($phoneNumber, "馃敃 Un asesor ya ha intervenido en la conversaci贸n, por favor espera su respuesta o utiliza *menu* para ver opciones."); } catch (Exception $e) { // ignore } @@ -504,6 +504,47 @@ class BotService { } } + /** + * Marcar la conversaci贸n como "en servicio" por un operador (Atender) + */ + public function attendConversation($phoneNumber, $operatorId = null) { + try { + $now = date('Y-m-d H:i:s'); + $update = ['in_service' => 1, 'in_service_at' => $now, 'advisor_requested' => 0]; + if ($operatorId) $update['in_service_by'] = $operatorId; + $this->db->update('users', $update, 'phone_number = :phone', ['phone' => $phoneNumber]); + + // Notificar al usuario + try { + $this->whatsappService->sendTextMessage($phoneNumber, "馃敂 Un asesor est谩 atendiendo tu conversaci贸n. Por favor, espera su respuesta."); + } catch (Exception $e) { + // ignore send errors + } + + // Registrar actividad del operador si hay informaci贸n disponible + $user = $this->db->fetch('SELECT id FROM users WHERE phone_number = :phone', ['phone' => $phoneNumber]); + $userId = $user['id'] ?? null; + $activity = [ + 'user_id' => $userId, + 'operator_id' => $operatorId, + 'action' => 'attend', + 'details' => 'Operator started attending the conversation', + 'created_at' => $now + ]; + try { + $this->db->insert('operator_activity', $activity); + } catch (Exception $e) { + if (function_exists('writeLog')) writeLog('WARN', 'Failed to insert operator_activity: ' . $e->getMessage()); + error_log('Failed to insert operator_activity: ' . $e->getMessage()); + } + + if (function_exists('writeLog')) writeLog('INFO', "Operator {$operatorId} attending conversation for {$phoneNumber}"); + } catch (Exception $e) { + error_log('attendConversation failed: ' . $e->getMessage()); + throw $e; + } + } + /** * Actualizar estado del men煤 del usuario */