up
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require_once '../config/config.php';
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
requireAuthentication();
|
||||
|
||||
try {
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
|
||||
$userId = isset($input['user_id']) ? intval($input['user_id']) : 0;
|
||||
if (!$userId) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => 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()]);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
+40
-1
@@ -475,7 +475,10 @@
|
||||
<span id="hold-indicator" style="display:none; margin-left:8px; color:#b85; font-weight:600">EN ESPERA</span>
|
||||
</h6>
|
||||
<small id="chat-phone">+1234567890</small>
|
||||
<div style="font-size:12px; margin-top:4px;"><button id="release-hold-btn" class="btn btn-sm btn-outline-primary" style="display:none">Liberar espera</button></div>
|
||||
<div style="font-size:12px; margin-top:4px;">
|
||||
<button id="attend-btn" class="btn btn-sm btn-outline-success" style="display:none; margin-right:6px;">Atender</button>
|
||||
<button id="release-hold-btn" class="btn btn-sm btn-outline-primary" style="display:none">Liberar espera</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: auto; display:flex; gap:8px; align-items:center;">
|
||||
<div id="bot-toggle-container" style="display:flex;align-items:center;gap:6px;margin-right:8px;">
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
$db = Database::getInstance();
|
||||
|
||||
try {
|
||||
$col = $db->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";
|
||||
}
|
||||
+42
-1
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user