This commit is contained in:
lizandrogd
2026-01-21 08:28:54 -05:00
parent 7d6c3b4fb4
commit 45a11032f5
59 changed files with 315 additions and 315 deletions
+1 -1
View File
@@ -212,7 +212,7 @@ https://tudominio.com/bot/api/webhook.php
4. En **Webhooks**: 4. En **Webhooks**:
- **Callback URL**: `https://tudominio.com/migrador/api/webhook.php` - **Callback URL**: `https://tudominio.com/migrador/api/webhook.php`
- **Verify Token**: `mi_token_secreto_123` (o cambia en config.php) - **Verify Token**: `mi_token_secreto_123` (o cambia en config.php)
- **Webhook fields**: ✅ `messages` - **Webhook fields**: ✅ `conversations`
### 3. Verificar Webhook ### 3. Verificar Webhook
```bash ```bash
+3 -3
View File
@@ -150,7 +150,7 @@ define('DB_CHARSET', 'utf8mb4');
2. Configuration → Webhook URL: 2. Configuration → Webhook URL:
https://tudominio.com/api/webhook.php https://tudominio.com/api/webhook.php
3. Verify Token: (copiar del dashboard) 3. Verify Token: (copiar del dashboard)
4. Suscribirse a: messages, message_status 4. Suscribirse a: conversations, message_status
``` ```
## 🚨 Solución de Problemas HestiaCP ## 🚨 Solución de Problemas HestiaCP
@@ -197,9 +197,9 @@ define('DB_CHARSET', 'utf8mb4');
### Performance ### Performance
```bash ```bash
1. Activar OPcache en PHP settings 1. Activar OPcache en PHP system_config
2. Configurar Redis/Memcached si disponible 2. Configurar Redis/Memcached si disponible
3. Optimizar MySQL en HestiaCP settings 3. Optimizar MySQL en HestiaCP system_config
4. Usar Cloudflare para CDN 4. Usar Cloudflare para CDN
``` ```
+1 -1
View File
@@ -28,7 +28,7 @@
2. Crear/configurar aplicación WhatsApp Business 2. Crear/configurar aplicación WhatsApp Business
3. Webhook URL: `https://tudominio.com/migrador/api/webhook.php` 3. Webhook URL: `https://tudominio.com/migrador/api/webhook.php`
4. Token de verificación: `mi_token_secreto_123` 4. Token de verificación: `mi_token_secreto_123`
5. Suscribirse a eventos: `messages` 5. Suscribirse a eventos: `conversations`
## 🎯 Prueba Rápida del Bot ## 🎯 Prueba Rápida del Bot
+3 -3
View File
@@ -62,7 +62,7 @@ chmod 666 config/config.php
2. **Configurar Webhook** 2. **Configurar Webhook**
- URL del Webhook: `https://tudominio.com/migrador/api/webhook.php` - URL del Webhook: `https://tudominio.com/migrador/api/webhook.php`
- Token de Verificación: `mi_token_secreto_123` - Token de Verificación: `mi_token_secreto_123`
- Suscribirse a: `messages` - Suscribirse a: `conversations`
3. **Obtener Tokens** 3. **Obtener Tokens**
- Token de Acceso (ya proporcionado) - Token de Acceso (ya proporcionado)
@@ -164,7 +164,7 @@ migrador/
- `conversations` - Historial de mensajes - `conversations` - Historial de mensajes
- `menus` - Configuración de menús - `menus` - Configuración de menús
- `menu_options` - Opciones de cada menú - `menu_options` - Opciones de cada menú
- `auto_responses` - Respuestas automáticas - `autoresponses` - Respuestas automáticas
- `system_config` - Configuración del sistema - `system_config` - Configuración del sistema
- `webhook_logs` - Logs de webhooks - `webhook_logs` - Logs de webhooks
@@ -186,7 +186,7 @@ INSERT INTO menu_options (menu_id, option_number, text, action_type, action_valu
### Respuestas Automáticas ### Respuestas Automáticas
```sql ```sql
-- Agregar respuesta automática -- Agregar respuesta automática
INSERT INTO auto_responses (trigger_type, trigger_value, response_text) VALUES INSERT INTO autoresponses (trigger_type, trigger_value, response_text) VALUES
('keyword', 'precio', 'Para consultar precios, escribe *catalogo* o visita www.mitienda.com'), ('keyword', 'precio', 'Para consultar precios, escribe *catalogo* o visita www.mitienda.com'),
('keyword', 'horarios', 'Atendemos de Lunes a Viernes de 8am a 6pm'); ('keyword', 'horarios', 'Atendemos de Lunes a Viernes de 8am a 6pm');
``` ```
+1 -1
View File
@@ -99,7 +99,7 @@ Este script:
1. En Meta for Developers, configura el webhook: 1. En Meta for Developers, configura el webhook:
- URL: `https://tu-dominio.com/api/webhook.php` - URL: `https://tu-dominio.com/api/webhook.php`
- Verify Token: El mismo que configuraste en el paso anterior - Verify Token: El mismo que configuraste en el paso anterior
- Suscripciones: `messages`, `message_status` - Suscripciones: `conversations`, `message_status`
## 📚 Estructura de Archivos ## 📚 Estructura de Archivos
+1 -1
View File
@@ -94,7 +94,7 @@ Este validador te mostrará:
#### **Configurar Webhook:** #### **Configurar Webhook:**
1. URL del webhook: `https://tudominio.com/api/webhook.php` 1. URL del webhook: `https://tudominio.com/api/webhook.php`
2. Token de verificación: (el que configuraste en .env) 2. Token de verificación: (el que configuraste en .env)
3. Eventos a suscribirse: `messages` 3. Eventos a suscribirse: `conversations`
### 5. **Acceso al Panel de Administración** ### 5. **Acceso al Panel de Administración**
+3 -3
View File
@@ -160,7 +160,7 @@ downloadMedia($mediaId)
-`get_conversation_list.php` - Lista simplificada -`get_conversation_list.php` - Lista simplificada
-`get_conversation_detail.php` - Detalle de conversación -`get_conversation_detail.php` - Detalle de conversación
-`get_conversation_stats.php` - Estadísticas -`get_conversation_stats.php` - Estadísticas
-`get_recent_messages.php` - Mensajes recientes -`get_recent_conversations.php` - Mensajes recientes
### 🍽️ Menús: ### 🍽️ Menús:
-`get_menus.php` - Listar menús -`get_menus.php` - Listar menús
@@ -188,8 +188,8 @@ downloadMedia($mediaId)
-`send_media_message.php` - Enviar multimedia -`send_media_message.php` - Enviar multimedia
### ⚙️ Configuración: ### ⚙️ Configuración:
-`get_settings.php` - Obtener configuración -`get_system_config.php` - Obtener configuración
-`save_settings.php` - Guardar configuración -`save_system_config.php` - Guardar configuración
-`manage_config.php` - Gestión completa -`manage_config.php` - Gestión completa
### 📝 Logs: ### 📝 Logs:
+2 -2
View File
@@ -46,10 +46,10 @@ function requireAuthentication() {
### 3. APIs protegidas ### 3. APIs protegidas
Archivos corregidos con `requireAuthentication()`: Archivos corregidos con `requireAuthentication()`:
-`api/get_stats.php` -`api/get_stats.php`
-`api/save_settings.php` -`api/save_system_config.php`
-`api/get_users.php` -`api/get_users.php`
-`api/send_message.php` -`api/send_message.php`
-`api/get_settings.php` -`api/get_system_config.php`
-`api/get_menus.php` -`api/get_menus.php`
-`api/export_users.php` -`api/export_users.php`
+3 -3
View File
@@ -69,10 +69,10 @@ try {
try { try {
// Eliminar mensajes relacionados usando PDO // Eliminar mensajes relacionados usando PDO
$stmt = $conn->prepare("DELETE FROM messages WHERE user_id = ?"); $stmt = $conn->prepare("DELETE FROM conversations WHERE user_id = ?");
$stmt->bindValue(1, $user_id, PDO::PARAM_INT); $stmt->bindValue(1, $user_id, PDO::PARAM_INT);
$stmt->execute(); $stmt->execute();
$deleted_messages = $stmt->rowCount(); $deleted_conversations = $stmt->rowCount();
// Eliminar el usuario // Eliminar el usuario
$stmt = $conn->prepare("DELETE FROM users WHERE id = ?"); $stmt = $conn->prepare("DELETE FROM users WHERE id = ?");
@@ -94,7 +94,7 @@ try {
'deleted_user_id' => $user_id, 'deleted_user_id' => $user_id,
'deleted_user_name' => $user_data['name'], 'deleted_user_name' => $user_data['name'],
'deleted_user_phone' => $user_data['phone_number'], 'deleted_user_phone' => $user_data['phone_number'],
'deleted_messages_count' => $deleted_messages, 'deleted_conversations_count' => $deleted_conversations,
'timestamp' => date('Y-m-d H:i:s') 'timestamp' => date('Y-m-d H:i:s')
] ]
]); ]);
+2 -2
View File
@@ -27,7 +27,7 @@ try {
u.status, u.status,
u.created_at, u.created_at,
u.updated_at, u.updated_at,
COUNT(c.id) as total_messages, COUNT(c.id) as total_conversations,
MAX(c.created_at) as last_activity MAX(c.created_at) as last_activity
FROM users u FROM users u
LEFT JOIN conversations c ON u.id = c.user_id LEFT JOIN conversations c ON u.id = c.user_id
@@ -61,7 +61,7 @@ try {
$user['name'] ?? 'Sin nombre', $user['name'] ?? 'Sin nombre',
$user['email'] ?? 'Sin email', $user['email'] ?? 'Sin email',
$user['status'], $user['status'],
$user['total_messages'], $user['total_conversations'],
$user['last_activity'] ? date('d/m/Y H:i', strtotime($user['last_activity'])) : 'Nunca', $user['last_activity'] ? date('d/m/Y H:i', strtotime($user['last_activity'])) : 'Nunca',
date('d/m/Y H:i', strtotime($user['created_at'])) date('d/m/Y H:i', strtotime($user['created_at']))
], ';'); ], ';');
+5 -5
View File
@@ -41,7 +41,7 @@ try {
} }
// Obtener todos los mensajes de la conversación // Obtener todos los mensajes de la conversación
$messages = $db->fetchAll( $conversations = $db->fetchAll(
"SELECT "SELECT
id, id,
message_id, message_id,
@@ -62,7 +62,7 @@ try {
); );
// Formatear mensajes // Formatear mensajes
$messages = array_map(function($msg) { $conversations = array_map(function($msg) {
return [ return [
'id' => intval($msg['id']), 'id' => intval($msg['id']),
'message_id' => $msg['message_id'] ?? '', 'message_id' => $msg['message_id'] ?? '',
@@ -75,7 +75,7 @@ try {
'time' => date('H:i', strtotime($msg['created_at'])), 'time' => date('H:i', strtotime($msg['created_at'])),
'date' => date('d/m/Y', strtotime($msg['created_at'])) 'date' => date('d/m/Y', strtotime($msg['created_at']))
]; ];
}, $messages); }, $conversations);
// Marcar mensajes como leídos // Marcar mensajes como leídos
$db->query( $db->query(
@@ -90,8 +90,8 @@ try {
'phone_number' => $user['phone_number'], 'phone_number' => $user['phone_number'],
'name' => $user['name'] ?? $user['phone_number'] 'name' => $user['name'] ?? $user['phone_number']
], ],
'messages' => $messages, 'conversations' => $conversations,
'total_messages' => count($messages) 'total_conversations' => count($conversations)
]); ]);
} catch (Exception $e) { } catch (Exception $e) {
+2 -2
View File
@@ -31,7 +31,7 @@ try {
c.message_type as last_message_type, c.message_type as last_message_type,
c.created_at as last_message_time, c.created_at as last_message_time,
c.status as last_message_status, c.status as last_message_status,
COUNT(*) as total_messages, COUNT(*) as total_conversations,
SUM(CASE WHEN c.direction = 'incoming' AND c.status = 'received' THEN 1 ELSE 0 END) as unread_count SUM(CASE WHEN c.direction = 'incoming' AND c.status = 'received' THEN 1 ELSE 0 END) as unread_count
FROM users u FROM users u
LEFT JOIN conversations c ON u.id = c.user_id LEFT JOIN conversations c ON u.id = c.user_id
@@ -61,7 +61,7 @@ try {
'last_message_type' => $conv['last_message_type'] ?? 'text', 'last_message_type' => $conv['last_message_type'] ?? 'text',
'last_message_time' => $conv['last_message_time'], 'last_message_time' => $conv['last_message_time'],
'last_message_status' => $conv['last_message_status'] ?? 'sent', 'last_message_status' => $conv['last_message_status'] ?? 'sent',
'total_messages' => intval($conv['total_messages']), 'total_conversations' => intval($conv['total_conversations']),
'unread_count' => intval($conv['unread_count']), 'unread_count' => intval($conv['unread_count']),
'time_ago' => timeAgo($conv['last_message_time']) 'time_ago' => timeAgo($conv['last_message_time'])
]; ];
+4 -4
View File
@@ -33,10 +33,10 @@ try {
// En el futuro, esto consultaría la base de datos real // En el futuro, esto consultaría la base de datos real
$stats = [ $stats = [
'user_id' => $user_id, 'user_id' => $user_id,
'total_messages' => rand(10, 100), 'total_conversations' => rand(10, 100),
'messages_today' => rand(0, 15), 'conversations_today' => rand(0, 15),
'messages_this_week' => rand(5, 50), 'conversations_this_week' => rand(5, 50),
'messages_this_month' => rand(20, 80), 'conversations_this_month' => rand(20, 80),
'first_message_date' => date('Y-m-d H:i:s', strtotime('-' . rand(1, 30) . ' days')), 'first_message_date' => date('Y-m-d H:i:s', strtotime('-' . rand(1, 30) . ' days')),
'last_message_date' => date('Y-m-d H:i:s', strtotime('-' . rand(1, 24) . ' hours')), 'last_message_date' => date('Y-m-d H:i:s', strtotime('-' . rand(1, 24) . ' hours')),
'avg_response_time' => rand(5, 120) . ' minutos', 'avg_response_time' => rand(5, 120) . ' minutos',
+3 -3
View File
@@ -14,7 +14,7 @@ header('Access-Control-Allow-Headers: Content-Type');
try { try {
$db = Database::getInstance(); $db = Database::getInstance();
$recentMessages = $db->fetchAll( $recentconversations = $db->fetchAll(
"SELECT "SELECT
c.content, c.content,
c.direction, c.direction,
@@ -29,10 +29,10 @@ try {
LIMIT 10" LIMIT 10"
); );
echo json_encode($recentMessages); echo json_encode($recentconversations);
} catch (Exception $e) { } catch (Exception $e) {
error_log("Error in get_recent_messages.php: " . $e->getMessage()); error_log("Error in get_recent_conversations.php: " . $e->getMessage());
http_response_code(500); http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor']); echo json_encode(['error' => 'Error interno del servidor']);
} }
+4 -4
View File
@@ -21,15 +21,15 @@ try {
"SELECT config_key, config_value FROM system_config" "SELECT config_key, config_value FROM system_config"
); );
$settings = []; $system_config = [];
foreach ($configs as $config) { foreach ($configs as $config) {
$settings[$config['config_key']] = $config['config_value']; $system_config[$config['config_key']] = $config['config_value'];
} }
echo json_encode($settings); echo json_encode($system_config);
} catch (Exception $e) { } catch (Exception $e) {
error_log("Error in get_settings.php: " . $e->getMessage()); error_log("Error in get_system_config.php: " . $e->getMessage());
http_response_code(500); http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor']); echo json_encode(['error' => 'Error interno del servidor']);
} }
+4 -4
View File
@@ -28,7 +28,7 @@ try {
$totalUsers = $db->fetch("SELECT COUNT(*) as count FROM users")['count']; $totalUsers = $db->fetch("SELECT COUNT(*) as count FROM users")['count'];
// Mensajes hoy // Mensajes hoy
$messagesToday = $db->fetch( $conversationsToday = $db->fetch(
"SELECT COUNT(*) as count FROM conversations WHERE DATE(created_at) = CURDATE()" "SELECT COUNT(*) as count FROM conversations WHERE DATE(created_at) = CURDATE()"
)['count']; )['count'];
@@ -39,13 +39,13 @@ try {
)['count']; )['count'];
// Total de mensajes // Total de mensajes
$totalMessages = $db->fetch("SELECT COUNT(*) as count FROM conversations")['count']; $totalconversations = $db->fetch("SELECT COUNT(*) as count FROM conversations")['count'];
$stats = [ $stats = [
'total_users' => (int)$totalUsers, 'total_users' => (int)$totalUsers,
'messages_today' => (int)$messagesToday, 'conversations_today' => (int)$conversationsToday,
'active_users' => (int)$activeUsers, 'active_users' => (int)$activeUsers,
'total_messages' => (int)$totalMessages 'total_conversations' => (int)$totalconversations
]; ];
echo json_encode($stats); echo json_encode($stats);
+10 -10
View File
@@ -26,7 +26,7 @@ try {
$db = Database::getInstance(); $db = Database::getInstance();
// Obtener mensajes del usuario (de ambas tablas para compatibilidad) // Obtener mensajes del usuario (de ambas tablas para compatibilidad)
$messages = $db->fetchAll( $conversations = $db->fetchAll(
"SELECT "SELECT
id, id,
user_id, user_id,
@@ -55,15 +55,15 @@ try {
status, status,
created_at, created_at,
1 as is_read 1 as is_read
FROM messages FROM conversations
WHERE user_id = :user_id WHERE user_id = :user_id
ORDER BY created_at ASC", ORDER BY created_at ASC",
['user_id' => $userId] ['user_id' => $userId]
); );
// Si no hay mensajes en conversations, intentar con messages // Si no hay mensajes en conversations, intentar con conversations
if (empty($messages)) { if (empty($conversations)) {
$messages = $db->fetchAll( $conversations = $db->fetchAll(
"SELECT "SELECT
id, id,
user_id, user_id,
@@ -72,7 +72,7 @@ try {
message_type, message_type,
status, status,
created_at created_at
FROM messages FROM conversations
WHERE user_id = :user_id WHERE user_id = :user_id
ORDER BY created_at ASC", ORDER BY created_at ASC",
['user_id' => $userId] ['user_id' => $userId]
@@ -80,7 +80,7 @@ try {
} }
// Formatear fechas y limpiar datos // Formatear fechas y limpiar datos
$messages = array_map(function($msg) { $conversations = array_map(function($msg) {
return [ return [
'id' => intval($msg['id']), 'id' => intval($msg['id']),
'user_id' => intval($msg['user_id']), 'user_id' => intval($msg['user_id']),
@@ -93,12 +93,12 @@ try {
'status' => $msg['status'] ?? 'sent', 'status' => $msg['status'] ?? 'sent',
'created_at' => $msg['created_at'] 'created_at' => $msg['created_at']
]; ];
}, $messages); }, $conversations);
echo json_encode($messages); echo json_encode($conversations);
} catch (Exception $e) { } catch (Exception $e) {
error_log("Error in get_user_messages.php: " . $e->getMessage()); error_log("Error in get_user_conversations.php: " . $e->getMessage());
http_response_code(500); http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor']); echo json_encode(['error' => 'Error interno del servidor']);
} }
+3 -3
View File
@@ -40,7 +40,7 @@ try {
$offset = ($page - 1) * $limit; $offset = ($page - 1) * $limit;
$sinceId = isset($_GET['since_id']) ? intval($_GET['since_id']) : null; $sinceId = isset($_GET['since_id']) ? intval($_GET['since_id']) : null;
$search = trim($_GET['search'] ?? ''); $search = trim($_GET['search'] ?? '');
$filter = trim($_GET['filter'] ?? ''); // e.g., HAS_MESSAGES $filter = trim($_GET['filter'] ?? ''); // e.g., HAS_conversations
$where = []; $where = [];
$params = []; $params = [];
@@ -55,9 +55,9 @@ try {
$params[] = "%{$search}%"; $params[] = "%{$search}%";
} }
if ($filter === 'HAS_MESSAGES') { if ($filter === 'HAS_conversations') {
$where[] = 'request_body LIKE ?'; $where[] = 'request_body LIKE ?';
$params[] = '%"messages"%'; $params[] = '%"conversations"%';
} }
$whereClause = empty($where) ? '' : 'WHERE ' . implode(' AND ', $where); $whereClause = empty($where) ? '' : 'WHERE ' . implode(' AND ', $where);
+1 -1
View File
@@ -85,7 +85,7 @@ try {
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log("Error in save_settings.php: " . $e->getMessage()); error_log("Error in save_system_config.php: " . $e->getMessage());
http_response_code(500); http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor: ' . $e->getMessage()]); echo json_encode(['error' => 'Error interno del servidor: ' . $e->getMessage()]);
} }
+2 -2
View File
@@ -133,7 +133,7 @@ try {
} }
// Guardar respuesta en base de datos // Guardar respuesta en base de datos
if ($response && isset($response['messages'][0]['id'])) { if ($response && isset($response['conversations'][0]['id'])) {
error_log("send_media_message.php - Respuesta de WhatsApp exitosa: " . json_encode($response)); error_log("send_media_message.php - Respuesta de WhatsApp exitosa: " . json_encode($response));
// Guardar en base de datos // Guardar en base de datos
@@ -149,7 +149,7 @@ try {
// Datos base para insertar // Datos base para insertar
$conversationData = [ $conversationData = [
'user_id' => $user['id'], 'user_id' => $user['id'],
'message_id' => $response['messages'][0]['id'], 'message_id' => $response['conversations'][0]['id'],
'direction' => 'outgoing', 'direction' => 'outgoing',
'message_type' => $mediaType, 'message_type' => $mediaType,
'content' => $caption ?? $filename ?? '', 'content' => $caption ?? $filename ?? '',
+1 -1
View File
@@ -470,7 +470,7 @@ try {
$response = $whatsappService->sendTextMessage($user['phone_number'], $message); $response = $whatsappService->sendTextMessage($user['phone_number'], $message);
if ($response && isset($response['messages']) && !empty($response['messages'])) { if ($response && isset($response['conversations']) && !empty($response['conversations'])) {
// Saving handled by WhatsAppService->saveOutgoingMessage(), skip manual insert to avoid duplicates // Saving handled by WhatsAppService->saveOutgoingMessage(), skip manual insert to avoid duplicates
echo json_encode([ echo json_encode([
'success' => true, 'success' => true,
+10 -10
View File
@@ -80,8 +80,8 @@ class WhatsAppWebhook {
foreach ($data['entry'] as $entry) { foreach ($data['entry'] as $entry) {
if (isset($entry['changes'])) { if (isset($entry['changes'])) {
foreach ($entry['changes'] as $change) { foreach ($entry['changes'] as $change) {
if ($change['field'] === 'messages') { if ($change['field'] === 'conversations') {
$this->processMessages($change['value']); $this->processconversations($change['value']);
} }
} }
} }
@@ -96,12 +96,12 @@ class WhatsAppWebhook {
} }
} }
private function processMessages($value) { private function processconversations($value) {
if (!isset($value['messages'])) { if (!isset($value['conversations'])) {
return; return;
} }
foreach ($value['messages'] as $message) { foreach ($value['conversations'] as $message) {
$phoneNumber = $message['from']; $phoneNumber = $message['from'];
$messageId = $message['id']; $messageId = $message['id'];
$timestamp = $message['timestamp']; $timestamp = $message['timestamp'];
@@ -209,11 +209,11 @@ class WhatsAppWebhook {
// Procesar estados de mensajes (entregado, leído, etc.) // Procesar estados de mensajes (entregado, leído, etc.)
if (isset($value['statuses'])) { if (isset($value['statuses'])) {
$this->processMessageStatuses($value['statuses']); $this->processconversationstatuses($value['statuses']);
} }
} }
private function processMessageStatuses($statuses) { private function processconversationstatuses($statuses) {
foreach ($statuses as $status) { foreach ($statuses as $status) {
$messageId = $status['id']; $messageId = $status['id'];
$newStatus = $status['status']; // sent, delivered, read, failed $newStatus = $status['status']; // sent, delivered, read, failed
@@ -294,11 +294,11 @@ class WhatsAppWebhook {
if (isset($entry['changes'])) { if (isset($entry['changes'])) {
foreach ($entry['changes'] as $change) { foreach ($entry['changes'] as $change) {
error_log("processPayload: processing change field=" . ($change['field'] ?? '')); error_log("processPayload: processing change field=" . ($change['field'] ?? ''));
if (($change['field'] ?? '') === 'messages' && isset($change['value'])) { if (($change['field'] ?? '') === 'conversations' && isset($change['value'])) {
try { try {
$this->processMessages($change['value']); $this->processconversations($change['value']);
} catch (Exception $e) { } catch (Exception $e) {
error_log("processPayload: processMessages failed: " . $e->getMessage()); error_log("processPayload: processconversations failed: " . $e->getMessage());
} }
} }
} }
+1 -1
View File
@@ -548,7 +548,7 @@ body {
border-left: 4px solid var(--info-color); border-left: 4px solid var(--info-color);
} }
/* Recent Messages */ /* Recent conversations */
.recent-message { .recent-message {
padding: 10px 15px; padding: 10px 15px;
border-radius: 8px; border-radius: 8px;
+36 -36
View File
@@ -52,11 +52,11 @@ class WhatsAppBotManager {
setupFormListeners() { setupFormListeners() {
// Formulario de configuración // Formulario de configuración
const settingsForm = document.getElementById('settings-form'); const system_configForm = document.getElementById('system_config-form');
if (settingsForm) { if (system_configForm) {
settingsForm.addEventListener('submit', (e) => { system_configForm.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
this.saveSettings(); this.savesystem_config();
}); });
} }
@@ -149,7 +149,7 @@ class WhatsAppBotManager {
case 'menus': case 'menus':
this.loadMenus(); this.loadMenus();
break; break;
case 'messages': case 'conversations':
this.loadMessageUsers(); this.loadMessageUsers();
break; break;
case 'templates': case 'templates':
@@ -158,8 +158,8 @@ class WhatsAppBotManager {
case 'autoresponses': case 'autoresponses':
this.loadAutoResponses(); this.loadAutoResponses();
break; break;
case 'settings': case 'system_config':
this.loadSettings(); this.loadsystem_config();
break; break;
case 'logs': case 'logs':
this.loadLogs(); this.loadLogs();
@@ -172,12 +172,12 @@ class WhatsAppBotManager {
const stats = await this.apiCall('get_stats.php'); const stats = await this.apiCall('get_stats.php');
this.updateStats(stats); this.updateStats(stats);
const recentMessagesResponse = await this.apiCall('get_recent_messages.php'); const recentconversationsResponse = await this.apiCall('get_recent_conversations.php');
if (recentMessagesResponse && recentMessagesResponse.success && Array.isArray(recentMessagesResponse.data)) { if (recentconversationsResponse && recentconversationsResponse.success && Array.isArray(recentconversationsResponse.data)) {
this.updateRecentMessages(recentMessagesResponse.data); this.updateRecentconversations(recentconversationsResponse.data);
} else if (recentMessagesResponse && Array.isArray(recentMessagesResponse)) { } else if (recentconversationsResponse && Array.isArray(recentconversationsResponse)) {
// Retrocompatibilidad por si la API devuelve directamente el array // Retrocompatibilidad por si la API devuelve directamente el array
this.updateRecentMessages(recentMessagesResponse); this.updateRecentconversations(recentconversationsResponse);
} }
this.updateChart(); this.updateChart();
@@ -189,20 +189,20 @@ class WhatsAppBotManager {
updateStats(stats) { updateStats(stats) {
if (stats) { if (stats) {
document.getElementById('total-users').textContent = stats.total_users || 0; document.getElementById('total-users').textContent = stats.total_users || 0;
document.getElementById('messages-today').textContent = stats.messages_today || 0; document.getElementById('conversations-today').textContent = stats.conversations_today || 0;
document.getElementById('active-users').textContent = stats.active_users || 0; document.getElementById('active-users').textContent = stats.active_users || 0;
document.getElementById('total-messages').textContent = stats.total_messages || 0; document.getElementById('total-conversations').textContent = stats.total_conversations || 0;
} }
} }
updateRecentMessages(messages) { updateRecentconversations(conversations) {
const container = document.getElementById('recent-messages'); const container = document.getElementById('recent-conversations');
if (!container) return; if (!container) return;
container.innerHTML = ''; container.innerHTML = '';
if (messages && messages.length > 0) { if (conversations && conversations.length > 0) {
messages.forEach(message => { conversations.forEach(message => {
const messageElement = this.createRecentMessageElement(message); const messageElement = this.createRecentMessageElement(message);
container.appendChild(messageElement); container.appendChild(messageElement);
}); });
@@ -230,9 +230,9 @@ class WhatsAppBotManager {
} }
setupCharts() { setupCharts() {
const ctx = document.getElementById('messagesChart'); const ctx = document.getElementById('conversationsChart');
if (ctx) { if (ctx) {
this.charts.messages = new Chart(ctx, { this.charts.conversations = new Chart(ctx, {
type: 'line', type: 'line',
data: { data: {
labels: [], labels: [],
@@ -275,10 +275,10 @@ class WhatsAppBotManager {
async updateChart() { async updateChart() {
try { try {
const chartData = await this.apiCall('get_chart_data.php'); const chartData = await this.apiCall('get_chart_data.php');
if (chartData && this.charts.messages) { if (chartData && this.charts.conversations) {
this.charts.messages.data.labels = chartData.labels; this.charts.conversations.data.labels = chartData.labels;
this.charts.messages.data.datasets[0].data = chartData.data; this.charts.conversations.data.datasets[0].data = chartData.data;
this.charts.messages.update(); this.charts.conversations.update();
} }
} catch (error) { } catch (error) {
console.error('Error updating chart:', error); console.error('Error updating chart:', error);
@@ -725,7 +725,7 @@ class WhatsAppBotManager {
} }
} }
async saveSettings() { async savesystem_config() {
const formData = { const formData = {
whatsapp_token: document.getElementById('whatsapp-token').value, whatsapp_token: document.getElementById('whatsapp-token').value,
phone_number_id: document.getElementById('phone-number-id').value, phone_number_id: document.getElementById('phone-number-id').value,
@@ -736,7 +736,7 @@ class WhatsAppBotManager {
try { try {
this.showLoading('Guardando configuración...'); this.showLoading('Guardando configuración...');
const result = await this.apiCall('save_settings.php', 'POST', formData); const result = await this.apiCall('save_system_config.php', 'POST', formData);
if (result.success) { if (result.success) {
this.showSuccess('Configuración guardada correctamente'); this.showSuccess('Configuración guardada correctamente');
@@ -750,16 +750,16 @@ class WhatsAppBotManager {
} }
} }
async loadSettings() { async loadsystem_config() {
try { try {
const settings = await this.apiCall('get_settings.php'); const system_config = await this.apiCall('get_system_config.php');
if (settings) { if (system_config) {
document.getElementById('whatsapp-token').value = settings.whatsapp_token || ''; document.getElementById('whatsapp-token').value = system_config.whatsapp_token || '';
document.getElementById('phone-number-id').value = settings.phone_number_id || ''; document.getElementById('phone-number-id').value = system_config.phone_number_id || '';
document.getElementById('webhook-token').value = settings.webhook_token || ''; document.getElementById('webhook-token').value = system_config.webhook_token || '';
document.getElementById('business-name').value = settings.business_name || ''; document.getElementById('business-name').value = system_config.business_name || '';
document.getElementById('welcome-message').value = settings.welcome_message || ''; document.getElementById('welcome-message').value = system_config.welcome_message || '';
} }
} catch (error) { } catch (error) {
this.showError('Error cargando configuración: ' + error.message); this.showError('Error cargando configuración: ' + error.message);
@@ -1025,7 +1025,7 @@ class WhatsAppBotManager {
replyToUser(phoneNumber) { replyToUser(phoneNumber) {
document.getElementById('message-recipient').value = phoneNumber; document.getElementById('message-recipient').value = phoneNumber;
this.showTab('messages'); this.showTab('conversations');
} }
replyToMessage(messageId, userPhone) { replyToMessage(messageId, userPhone) {
@@ -1049,7 +1049,7 @@ class WhatsAppBotManager {
if (data.success) { if (data.success) {
this.showSuccess('Reacción enviada'); this.showSuccess('Reacción enviada');
// Refrescar mensajes // Refrescar mensajes
await this.loadMessages(this.currentUserId, false); await this.loadconversations(this.currentUserId, false);
} else { } else {
this.showError('Error enviando reacción: ' + (data.error || 'desconocido')); this.showError('Error enviando reacción: ' + (data.error || 'desconocido'));
} }
+45 -45
View File
@@ -46,11 +46,11 @@ class SimpleWhatsAppManager {
setupFormListeners() { setupFormListeners() {
// Formulario de configuración // Formulario de configuración
const settingsForm = document.getElementById('settings-form'); const system_configForm = document.getElementById('system_config-form');
if (settingsForm) { if (system_configForm) {
settingsForm.addEventListener('submit', (e) => { system_configForm.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
this.saveSettings(); this.savesystem_config();
}); });
} }
@@ -108,8 +108,8 @@ class SimpleWhatsAppManager {
case 'users': case 'users':
this.loadUsers(); this.loadUsers();
break; break;
case 'messages': case 'conversations':
this.loadMessages(); this.loadconversations();
break; break;
case 'templates': case 'templates':
this.loadTemplates(); this.loadTemplates();
@@ -123,8 +123,8 @@ class SimpleWhatsAppManager {
case 'logs': case 'logs':
this.loadLogs(); this.loadLogs();
break; break;
case 'settings': case 'system_config':
this.loadSettings(); this.loadsystem_config();
break; break;
default: default:
this.log(`Tab no reconocido: ${tabName}`, 'warning'); this.log(`Tab no reconocido: ${tabName}`, 'warning');
@@ -200,12 +200,12 @@ class SimpleWhatsAppManager {
this.updateStats(stats); this.updateStats(stats);
// Cargar mensajes recientes // Cargar mensajes recientes
const recentMessagesResponse = await this.apiCall('get_recent_messages.php'); const recentconversationsResponse = await this.apiCall('get_recent_conversations.php');
if (recentMessagesResponse && recentMessagesResponse.success && Array.isArray(recentMessagesResponse.data)) { if (recentconversationsResponse && recentconversationsResponse.success && Array.isArray(recentconversationsResponse.data)) {
this.updateRecentMessages(recentMessagesResponse.data); this.updateRecentconversations(recentconversationsResponse.data);
} else if (recentMessagesResponse && Array.isArray(recentMessagesResponse)) { } else if (recentconversationsResponse && Array.isArray(recentconversationsResponse)) {
// Retrocompatibilidad por si la API devuelve directamente el array // Retrocompatibilidad por si la API devuelve directamente el array
this.updateRecentMessages(recentMessagesResponse); this.updateRecentconversations(recentconversationsResponse);
} }
// Actualizar gráfico si existe // Actualizar gráfico si existe
@@ -222,9 +222,9 @@ class SimpleWhatsAppManager {
if (stats) { if (stats) {
const elements = [ const elements = [
{ id: 'total-users', value: stats.total_users || 0 }, { id: 'total-users', value: stats.total_users || 0 },
{ id: 'messages-today', value: stats.messages_today || 0 }, { id: 'conversations-today', value: stats.conversations_today || 0 },
{ id: 'active-users', value: stats.active_users || 0 }, { id: 'active-users', value: stats.active_users || 0 },
{ id: 'total-messages', value: stats.total_messages || 0 } { id: 'total-conversations', value: stats.total_conversations || 0 }
]; ];
elements.forEach(item => { elements.forEach(item => {
@@ -237,8 +237,8 @@ class SimpleWhatsAppManager {
} }
} }
updateRecentMessages(messages) { updateRecentconversations(conversations) {
const container = document.getElementById('recent-messages'); const container = document.getElementById('recent-conversations');
if (!container) { if (!container) {
this.log('Contenedor de mensajes recientes no encontrado', 'warning'); this.log('Contenedor de mensajes recientes no encontrado', 'warning');
return; return;
@@ -246,9 +246,9 @@ class SimpleWhatsAppManager {
container.innerHTML = ''; container.innerHTML = '';
if (messages && messages.length > 0) { if (conversations && conversations.length > 0) {
this.log(`Mostrando ${messages.length} mensajes recientes`); this.log(`Mostrando ${conversations.length} mensajes recientes`);
messages.forEach(message => { conversations.forEach(message => {
const messageElement = this.createRecentMessageElement(message); const messageElement = this.createRecentMessageElement(message);
container.appendChild(messageElement); container.appendChild(messageElement);
}); });
@@ -281,17 +281,17 @@ class SimpleWhatsAppManager {
} }
async updateChart() { async updateChart() {
if (!this.charts || !this.charts.messages) { if (!this.charts || !this.charts.conversations) {
this.log('Gráfico no inicializado, omitiendo actualización', 'warning'); this.log('Gráfico no inicializado, omitiendo actualización', 'warning');
return; return;
} }
try { try {
const chartData = await this.apiCall('get_chart_data.php'); const chartData = await this.apiCall('get_chart_data.php');
if (chartData && this.charts.messages) { if (chartData && this.charts.conversations) {
this.charts.messages.data.labels = chartData.labels || []; this.charts.conversations.data.labels = chartData.labels || [];
this.charts.messages.data.datasets[0].data = chartData.data || []; this.charts.conversations.data.datasets[0].data = chartData.data || [];
this.charts.messages.update(); this.charts.conversations.update();
this.log('Gráfico actualizado correctamente'); this.log('Gráfico actualizado correctamente');
} }
} catch (error) { } catch (error) {
@@ -300,7 +300,7 @@ class SimpleWhatsAppManager {
} }
setupCharts() { setupCharts() {
const ctx = document.getElementById('messagesChart'); const ctx = document.getElementById('conversationsChart');
if (!ctx) { if (!ctx) {
this.log('Canvas de gráfico no encontrado', 'warning'); this.log('Canvas de gráfico no encontrado', 'warning');
return; return;
@@ -313,7 +313,7 @@ class SimpleWhatsAppManager {
try { try {
this.charts = this.charts || {}; this.charts = this.charts || {};
this.charts.messages = new Chart(ctx, { this.charts.conversations = new Chart(ctx, {
type: 'line', type: 'line',
data: { data: {
labels: [], labels: [],
@@ -634,14 +634,14 @@ class SimpleWhatsAppManager {
return date.toLocaleDateString(); return date.toLocaleDateString();
} }
async loadSettings() { async loadsystem_config() {
this.log('Cargando configuraciones'); this.log('Cargando configuraciones');
try { try {
const response = await this.apiCall('manage_config.php?action=whatsapp'); const response = await this.apiCall('manage_config.php?action=whatsapp');
if (response && response.success) { if (response && response.success) {
this.updateSettingsForm(response.data); this.updatesystem_configForm(response.data);
} }
} catch (error) { } catch (error) {
@@ -649,7 +649,7 @@ class SimpleWhatsAppManager {
} }
} }
updateSettingsForm(data) { updatesystem_configForm(data) {
if (!data) return; if (!data) return;
const fields = [ const fields = [
@@ -672,10 +672,10 @@ class SimpleWhatsAppManager {
}); });
} }
async saveSettings() { async savesystem_config() {
this.log('Guardando configuraciones'); this.log('Guardando configuraciones');
const settings = { const system_config = {
token: document.getElementById('whatsapp-token').value, token: document.getElementById('whatsapp-token').value,
phone_number_id: document.getElementById('phone-number-id').value, phone_number_id: document.getElementById('phone-number-id').value,
webhook_verify_token: document.getElementById('webhook-token').value, webhook_verify_token: document.getElementById('webhook-token').value,
@@ -687,7 +687,7 @@ class SimpleWhatsAppManager {
try { try {
const response = await this.apiCall('manage_config.php?action=save_whatsapp', { const response = await this.apiCall('manage_config.php?action=save_whatsapp', {
method: 'POST', method: 'POST',
body: { whatsapp: settings } body: { whatsapp: system_config }
}); });
if (response && response.success) { if (response && response.success) {
@@ -741,7 +741,7 @@ class SimpleWhatsAppManager {
}, 5000); }, 5000);
} }
async loadMessages() { async loadconversations() {
this.log('Cargando interfaz de mensajes'); this.log('Cargando interfaz de mensajes');
try { try {
@@ -1606,7 +1606,7 @@ window.openChatWindow = function (userId) {
}; };
// Función para mostrar modal de chat // Función para mostrar modal de chat
function showChatModal(user, messages) { function showChatModal(user, conversations) {
// Escapar datos del usuario para evitar XSS // Escapar datos del usuario para evitar XSS
const userName = escapeHtml(user.name || 'Usuario'); const userName = escapeHtml(user.name || 'Usuario');
const userPhone = escapeHtml(user.phone_number || ''); const userPhone = escapeHtml(user.phone_number || '');
@@ -1623,8 +1623,8 @@ function showChatModal(user, messages) {
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body p-0"> <div class="modal-body p-0">
<div id="chat-messages" class="chat-container" style="height: 400px; overflow-y: auto; padding: 15px; background-color: #e5ddd5;"> <div id="chat-conversations" class="chat-container" style="height: 400px; overflow-y: auto; padding: 15px; background-color: #e5ddd5;">
${generateChatMessages(messages)} ${generateChatconversations(conversations)}
</div> </div>
<div class="border-top p-3"> <div class="border-top p-3">
<div class="row"> <div class="row">
@@ -1682,19 +1682,19 @@ function showChatModal(user, messages) {
// Scroll al final // Scroll al final
setTimeout(() => { setTimeout(() => {
const chatContainer = document.getElementById('chat-messages'); const chatContainer = document.getElementById('chat-conversations');
chatContainer.scrollTop = chatContainer.scrollHeight; chatContainer.scrollTop = chatContainer.scrollHeight;
}, 200); }, 200);
} }
// Generar HTML de mensajes del chat // Generar HTML de mensajes del chat
function generateChatMessages(messages) { function generateChatconversations(conversations) {
if (!messages || messages.length === 0) { if (!conversations || conversations.length === 0) {
return '<div class="text-center text-muted py-4"><i class="fas fa-comments fa-3x"></i><br><br>No hay mensajes en esta conversación</div>'; return '<div class="text-center text-muted py-4"><i class="fas fa-comments fa-3x"></i><br><br>No hay mensajes en esta conversación</div>';
} }
let html = ''; let html = '';
messages.forEach(msg => { conversations.forEach(msg => {
const isOutgoing = msg.direction === 'outgoing'; const isOutgoing = msg.direction === 'outgoing';
const messageClass = isOutgoing ? 'outgoing' : 'incoming'; const messageClass = isOutgoing ? 'outgoing' : 'incoming';
const alignClass = isOutgoing ? 'justify-content-end' : 'justify-content-start'; const alignClass = isOutgoing ? 'justify-content-end' : 'justify-content-start';
@@ -1878,8 +1878,8 @@ window.viewConversationDetails = async function (userId) {
// Obtener estadísticas de la conversación (simuladas por ahora) // Obtener estadísticas de la conversación (simuladas por ahora)
const stats = { const stats = {
total_messages: Math.floor(Math.random() * 50) + 1, total_conversations: Math.floor(Math.random() * 50) + 1,
messages_today: Math.floor(Math.random() * 10), conversations_today: Math.floor(Math.random() * 10),
last_activity: user.updated_at || user.created_at, last_activity: user.updated_at || user.created_at,
first_contact: user.created_at, first_contact: user.created_at,
status: user.status || 'active' status: user.status || 'active'
@@ -1948,11 +1948,11 @@ function showConversationDetailsModal(user, stats) {
<h6 class="text-muted mb-3"><i class="fas fa-chart-line"></i> Estadísticas de Conversación</h6> <h6 class="text-muted mb-3"><i class="fas fa-chart-line"></i> Estadísticas de Conversación</h6>
<div class="mb-3"> <div class="mb-3">
<strong>Total de Mensajes:</strong> <strong>Total de Mensajes:</strong>
<span class="badge bg-primary">${stats.total_messages || 0}</span> <span class="badge bg-primary">${stats.total_conversations || 0}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<strong>Mensajes Hoy:</strong> <strong>Mensajes Hoy:</strong>
<span class="badge bg-success">${stats.messages_today || 0}</span> <span class="badge bg-success">${stats.conversations_today || 0}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<strong>Última Actividad:</strong><br> <strong>Última Actividad:</strong><br>
+15 -15
View File
@@ -52,7 +52,7 @@ if (empty($user_id)) {
justify-content: space-between; justify-content: space-between;
} }
.chat-messages { .chat-conversations {
flex: 1; flex: 1;
padding: 20px; padding: 20px;
overflow-y: auto; overflow-y: auto;
@@ -367,7 +367,7 @@ if (empty($user_id)) {
</div> </div>
<!-- Mensajes del chat --> <!-- Mensajes del chat -->
<div class="chat-messages" id="chatMessages"> <div class="chat-conversations" id="chatconversations">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<div class="spinner-border text-primary" role="status"> <div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Cargando mensajes...</span> <span class="visually-hidden">Cargando mensajes...</span>
@@ -536,7 +536,7 @@ if (empty($user_id)) {
`<span>${(currentUser.name || 'U').charAt(0).toUpperCase()}</span>`; `<span>${(currentUser.name || 'U').charAt(0).toUpperCase()}</span>`;
// Cargar mensajes // Cargar mensajes
displayMessages(response.messages); displayconversations(response.conversations);
// Cargar plantillas // Cargar plantillas
loadTemplates(); loadTemplates();
@@ -551,11 +551,11 @@ if (empty($user_id)) {
} }
// Mostrar mensajes // Mostrar mensajes
function displayMessages(messages) { function displayconversations(conversations) {
const chatMessages = document.getElementById('chatMessages'); const chatconversations = document.getElementById('chatconversations');
if (!messages || messages.length === 0) { if (!conversations || conversations.length === 0) {
chatMessages.innerHTML = ` chatconversations.innerHTML = `
<div class="text-center text-muted py-5"> <div class="text-center text-muted py-5">
<i class="fas fa-comments fa-3x mb-3"></i> <i class="fas fa-comments fa-3x mb-3"></i>
<br>No hay mensajes en esta conversación <br>No hay mensajes en esta conversación
@@ -566,7 +566,7 @@ if (empty($user_id)) {
} }
let html = ''; let html = '';
messages.forEach(msg => { conversations.forEach(msg => {
const isOutgoing = msg.direction === 'outgoing'; const isOutgoing = msg.direction === 'outgoing';
const messageClass = isOutgoing ? 'message-outgoing' : 'message-incoming'; const messageClass = isOutgoing ? 'message-outgoing' : 'message-incoming';
@@ -643,7 +643,7 @@ if (empty($user_id)) {
`; `;
}); });
chatMessages.innerHTML = html; chatconversations.innerHTML = html;
scrollToBottom(); scrollToBottom();
} }
@@ -804,7 +804,7 @@ if (empty($user_id)) {
// Agregar mensaje a la vista // Agregar mensaje a la vista
function addMessageToView(message, direction) { function addMessageToView(message, direction) {
const chatMessages = document.getElementById('chatMessages'); const chatconversations = document.getElementById('chatconversations');
const isOutgoing = direction === 'outgoing'; const isOutgoing = direction === 'outgoing';
const messageClass = isOutgoing ? 'message-outgoing' : 'message-incoming'; const messageClass = isOutgoing ? 'message-outgoing' : 'message-incoming';
const now = new Date().toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' }); const now = new Date().toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });
@@ -820,7 +820,7 @@ if (empty($user_id)) {
</div> </div>
`; `;
chatMessages.insertAdjacentHTML('beforeend', messageHtml); chatconversations.insertAdjacentHTML('beforeend', messageHtml);
scrollToBottom(); scrollToBottom();
} }
@@ -835,8 +835,8 @@ if (empty($user_id)) {
// Scroll al final // Scroll al final
function scrollToBottom() { function scrollToBottom() {
const chatMessages = document.getElementById('chatMessages'); const chatconversations = document.getElementById('chatconversations');
chatMessages.scrollTop = chatMessages.scrollHeight; chatconversations.scrollTop = chatconversations.scrollHeight;
} }
// Refrescar chat // Refrescar chat
@@ -1146,7 +1146,7 @@ if (empty($user_id)) {
// Renderizar mensaje multimedia // Renderizar mensaje multimedia
function renderMediaMessage(message, type, timestamp = null) { function renderMediaMessage(message, type, timestamp = null) {
const chatMessages = document.getElementById('chatMessages'); const chatconversations = document.getElementById('chatconversations');
const messageDiv = document.createElement('div'); const messageDiv = document.createElement('div');
messageDiv.className = `message-bubble message-${type}`; messageDiv.className = `message-bubble message-${type}`;
@@ -1183,7 +1183,7 @@ if (empty($user_id)) {
} }
messageDiv.innerHTML = html; messageDiv.innerHTML = html;
chatMessages.appendChild(messageDiv); chatconversations.appendChild(messageDiv);
scrollToBottom(); scrollToBottom();
} }
+1 -1
View File
@@ -162,7 +162,7 @@ echo "<div class='ok'>• <strong>From phone number:</strong> Anota este número
echo "<br><div class='warning'><strong>4. CONFIGURAR WEBHOOK:</strong></div>"; echo "<br><div class='warning'><strong>4. CONFIGURAR WEBHOOK:</strong></div>";
echo "<div class='ok'>• URL del webhook: https://tudominio.com/api/webhook.php</div>"; echo "<div class='ok'>• URL del webhook: https://tudominio.com/api/webhook.php</div>";
echo "<div class='ok'>• Verify token: El mismo que ingreses arriba</div>"; echo "<div class='ok'>• Verify token: El mismo que ingreses arriba</div>";
echo "<div class='ok'>• Suscríbete a 'messages'</div>"; echo "<div class='ok'>• Suscríbete a 'conversations'</div>";
echo "<br><div class='error'><strong>⚠️ IMPORTANTE:</strong></div>"; echo "<br><div class='error'><strong>⚠️ IMPORTANTE:</strong></div>";
echo "<div class='error'>• El token temporal expira en 24 horas</div>"; echo "<div class='error'>• El token temporal expira en 24 horas</div>";
+21 -21
View File
@@ -156,7 +156,7 @@
color: #ccc; color: #ccc;
} }
.chat-messages { .chat-conversations {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 20px; padding: 20px;
@@ -485,7 +485,7 @@
</div> </div>
</div> </div>
<div class="chat-messages" id="chat-messages"> <div class="chat-conversations" id="chat-conversations">
<!-- Los mensajes se cargan aquí --> <!-- Los mensajes se cargan aquí -->
</div> </div>
@@ -530,7 +530,7 @@
this.currentConversationId = null; this.currentConversationId = null;
this.currentUserId = null; this.currentUserId = null;
this.conversations = []; this.conversations = [];
this.messages = []; this.conversations = [];
this.init(); this.init();
} }
@@ -671,7 +671,7 @@
// Actualizar mensajes del chat activo cada 10 segundos // Actualizar mensajes del chat activo cada 10 segundos
setInterval(() => { setInterval(() => {
if (this.currentUserId) { if (this.currentUserId) {
this.loadMessages(this.currentUserId, false); this.loadconversations(this.currentUserId, false);
} }
}, 10000); }, 10000);
} }
@@ -891,14 +891,14 @@
} }
// Cargar mensajes // Cargar mensajes
await this.loadMessages(userId); await this.loadconversations(userId);
// Cargar respuestas rápidas // Cargar respuestas rápidas
await this.loadQuickReplies(); await this.loadQuickReplies();
} }
async loadMessages(userId, showLoading = true) { async loadconversations(userId, showLoading = true) {
if (showLoading) { if (showLoading) {
document.getElementById('chat-messages').innerHTML = ` document.getElementById('chat-conversations').innerHTML = `
<div class="loading"> <div class="loading">
<i class="fas fa-spinner fa-spin"></i> Cargando mensajes... <i class="fas fa-spinner fa-spin"></i> Cargando mensajes...
</div> </div>
@@ -906,12 +906,12 @@
} }
try { try {
const response = await fetch(`api/get_user_messages.php?user_id=${userId}`); const response = await fetch(`api/get_user_conversations.php?user_id=${userId}`);
const data = await response.json(); const data = await response.json();
if (Array.isArray(data)) { if (Array.isArray(data)) {
this.messages = data; this.conversations = data;
this.renderMessages(); this.renderconversations();
this.scrollToBottom(); this.scrollToBottom();
// Marcar como leídos en el backend // Marcar como leídos en el backend
@@ -928,8 +928,8 @@
} }
} }
} catch (error) { } catch (error) {
console.error('Error loading messages:', error); console.error('Error loading conversations:', error);
document.getElementById('chat-messages').innerHTML = ` document.getElementById('chat-conversations').innerHTML = `
<div class="text-center p-4"> <div class="text-center p-4">
<i class="fas fa-exclamation-triangle text-warning"></i> <i class="fas fa-exclamation-triangle text-warning"></i>
<p>Error al cargar los mensajes</p> <p>Error al cargar los mensajes</p>
@@ -938,10 +938,10 @@
} }
} }
renderMessages() { renderconversations() {
const container = document.getElementById('chat-messages'); const container = document.getElementById('chat-conversations');
if (this.messages.length === 0) { if (this.conversations.length === 0) {
container.innerHTML = ` container.innerHTML = `
<div class="text-center p-4"> <div class="text-center p-4">
<i class="far fa-comment fa-3x text-muted mb-3"></i> <i class="far fa-comment fa-3x text-muted mb-3"></i>
@@ -951,7 +951,7 @@
return; return;
} }
const html = this.messages.map(msg => { const html = this.conversations.map(msg => {
const time = new Date(msg.created_at).toLocaleTimeString('es-ES', { const time = new Date(msg.created_at).toLocaleTimeString('es-ES', {
hour: '2-digit', hour: '2-digit',
minute: '2-digit' minute: '2-digit'
@@ -967,7 +967,7 @@
// Mostrar preview si es reply/context // Mostrar preview si es reply/context
let replyHtml = ''; let replyHtml = '';
if (msg.reply_to_message_id) { if (msg.reply_to_message_id) {
const target = this.messages.find(m => m.message_id == msg.reply_to_message_id); const target = this.conversations.find(m => m.message_id == msg.reply_to_message_id);
const previewText = target ? (target.content || target.message_text || '').substring(0,140) : ('Mensaje ' + msg.reply_to_message_id); const previewText = target ? (target.content || target.message_text || '').substring(0,140) : ('Mensaje ' + msg.reply_to_message_id);
replyHtml = `<div class="reply-preview">En respuesta a: ${previewText}</div>`; replyHtml = `<div class="reply-preview">En respuesta a: ${previewText}</div>`;
} }
@@ -1043,7 +1043,7 @@
}); });
const result = await resp.json(); const result = await resp.json();
if (result.success) { if (result.success) {
await this.loadMessages(this.currentUserId, false); await this.loadconversations(this.currentUserId, false);
await this.loadConversations(); await this.loadConversations();
} else { } else {
alert('Error al enviar plantilla: ' + (result.error || JSON.stringify(result))); alert('Error al enviar plantilla: ' + (result.error || JSON.stringify(result)));
@@ -1055,7 +1055,7 @@
} }
scrollToBottom() { scrollToBottom() {
const container = document.getElementById('chat-messages'); const container = document.getElementById('chat-conversations');
container.scrollTop = container.scrollHeight; container.scrollTop = container.scrollHeight;
} }
@@ -1090,7 +1090,7 @@
if (result.success) { if (result.success) {
input.value = ''; input.value = '';
// Recargar mensajes // Recargar mensajes
await this.loadMessages(this.currentUserId, false); await this.loadconversations(this.currentUserId, false);
// Actualizar lista de conversaciones // Actualizar lista de conversaciones
this.loadConversations(); this.loadConversations();
// Actualizar respuestas rápidas // Actualizar respuestas rápidas
@@ -1314,7 +1314,7 @@
// Éxito // Éxito
this.cancelMediaUpload(); this.cancelMediaUpload();
await this.loadMessages(this.currentUserId, false); await this.loadconversations(this.currentUserId, false);
this.loadConversations(); this.loadConversations();
} catch (error) { } catch (error) {
+1 -1
View File
@@ -163,7 +163,7 @@ if ($verification_success && $total_corrections > 0) {
echo "<br><div class='warning'><strong>SIGUIENTE PASO:</strong></div>"; echo "<br><div class='warning'><strong>SIGUIENTE PASO:</strong></div>";
echo "<div class='warning'>• Prueba cualquier endpoint de la API</div>"; echo "<div class='warning'>• Prueba cualquier endpoint de la API</div>";
echo "<div class='warning'>• Ejemplo: <a href='api/get_settings.php' style='color:#ffaa00'>api/get_settings.php</a></div>"; echo "<div class='warning'>• Ejemplo: <a href='api/get_system_config.php' style='color:#ffaa00'>api/get_system_config.php</a></div>";
echo "<div class='warning'>• O prueba el login: <a href='login.php' style='color:#ffaa00'>login.php</a></div>"; echo "<div class='warning'>• O prueba el login: <a href='login.php' style='color:#ffaa00'>login.php</a></div>";
} elseif ($total_corrections === 0) { } elseif ($total_corrections === 0) {
+9 -9
View File
@@ -74,7 +74,7 @@ try {
} }
// Crear conversaciones de muestra // Crear conversaciones de muestra
$sampleMessages = [ $sampleconversations = [
['text' => 'Hola, necesito información sobre sus servicios', 'direction' => 'incoming'], ['text' => 'Hola, necesito información sobre sus servicios', 'direction' => 'incoming'],
['text' => '¡Hola! Claro, te ayudo con gusto. ¿Qué tipo de servicio te interesa?', 'direction' => 'outgoing'], ['text' => '¡Hola! Claro, te ayudo con gusto. ¿Qué tipo de servicio te interesa?', 'direction' => 'outgoing'],
['text' => 'Estoy buscando precios de desarrollo web', 'direction' => 'incoming'], ['text' => 'Estoy buscando precios de desarrollo web', 'direction' => 'incoming'],
@@ -87,15 +87,15 @@ try {
['text' => 'Por supuesto! Cuéntanos qué problema tienes', 'direction' => 'outgoing'] ['text' => 'Por supuesto! Cuéntanos qué problema tienes', 'direction' => 'outgoing']
]; ];
$messagesCreated = 0; $conversationsCreated = 0;
foreach ($userIds as $index => $userId) { foreach ($userIds as $index => $userId) {
// Crear 2-3 mensajes por usuario // Crear 2-3 mensajes por usuario
$messageCount = rand(2, 4); $messageCount = rand(2, 4);
for ($i = 0; $i < $messageCount; $i++) { for ($i = 0; $i < $messageCount; $i++) {
$messageIndex = ($index * $messageCount + $i) % count($sampleMessages); $messageIndex = ($index * $messageCount + $i) % count($sampleconversations);
$message = $sampleMessages[$messageIndex]; $message = $sampleconversations[$messageIndex];
$messageData = [ $messageData = [
'user_id' => $userId, 'user_id' => $userId,
@@ -120,12 +120,12 @@ try {
$messageData['status'], $messageData['status'],
$messageData['created_at'] $messageData['created_at']
]); ]);
$messagesCreated++; $conversationsCreated++;
} catch (Exception $e) { } catch (Exception $e) {
// Si falla, intentar en messages // Si falla, intentar en conversations
try { try {
$stmt = $pdo->prepare(" $stmt = $pdo->prepare("
INSERT INTO messages (user_id, message_text, direction, message_type, status, created_at) INSERT INTO conversations (user_id, message_text, direction, message_type, status, created_at)
VALUES (?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?)
"); ");
$stmt->execute([ $stmt->execute([
@@ -136,7 +136,7 @@ try {
$messageData['status'], $messageData['status'],
$messageData['created_at'] $messageData['created_at']
]); ]);
$messagesCreated++; $conversationsCreated++;
} catch (Exception $e2) { } catch (Exception $e2) {
echo "<div class='error'>❌ Error creando mensaje: " . $e2->getMessage() . "</div>"; echo "<div class='error'>❌ Error creando mensaje: " . $e2->getMessage() . "</div>";
} }
@@ -145,7 +145,7 @@ try {
} }
echo "<div class='ok'>✅ Usuarios creados: " . count($userIds) . "</div>"; echo "<div class='ok'>✅ Usuarios creados: " . count($userIds) . "</div>";
echo "<div class='ok'>✅ Mensajes/conversaciones creados: $messagesCreated</div>"; echo "<div class='ok'>✅ Mensajes/conversaciones creados: $conversationsCreated</div>";
echo "<div class='ok'>🎉 ¡Datos de prueba creados exitosamente!</div>"; echo "<div class='ok'>🎉 ¡Datos de prueba creados exitosamente!</div>";
echo "<br><div class='warning'><strong>SIGUIENTE PASO:</strong></div>"; echo "<br><div class='warning'><strong>SIGUIENTE PASO:</strong></div>";
+2 -2
View File
@@ -69,7 +69,7 @@ CREATE TABLE menu_options (
); );
-- Tabla de respuestas automáticas -- Tabla de respuestas automáticas
CREATE TABLE auto_responses ( CREATE TABLE autoresponses (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
trigger_type ENUM('keyword', 'menu_selection', 'welcome') NOT NULL, trigger_type ENUM('keyword', 'menu_selection', 'welcome') NOT NULL,
trigger_value VARCHAR(200), trigger_value VARCHAR(200),
@@ -167,7 +167,7 @@ INSERT INTO menu_options (menu_id, option_number, text, action_type, action_valu
(@support_menu_id, 0, '🔙 Volver al menú principal', 'menu', 'main_menu'); (@support_menu_id, 0, '🔙 Volver al menú principal', 'menu', 'main_menu');
-- Insertar respuestas automáticas -- Insertar respuestas automáticas
INSERT INTO auto_responses (trigger_type, trigger_value, response_text) VALUES INSERT INTO autoresponses (trigger_type, trigger_value, response_text) VALUES
('keyword', 'menu', 'Aquí tienes nuestro menú principal:'), ('keyword', 'menu', 'Aquí tienes nuestro menú principal:'),
('keyword', 'hola', '¡Hola! 👋 Escribe *menu* para ver nuestras opciones.'), ('keyword', 'hola', '¡Hola! 👋 Escribe *menu* para ver nuestras opciones.'),
('keyword', 'ayuda', 'Estoy aquí para ayudarte. Escribe *menu* para ver las opciones disponibles.'), ('keyword', 'ayuda', 'Estoy aquí para ayudarte. Escribe *menu* para ver las opciones disponibles.'),
+2 -2
View File
@@ -12,7 +12,7 @@ tr:nth-child(even) { background-color: #f2f2f2; }
pre { background: #f4f4f4; padding: 10px; overflow-x: auto; } pre { background: #f4f4f4; padding: 10px; overflow-x: auto; }
</style>"; </style>";
$messages = $db->fetchAll(" $conversations = $db->fetchAll("
SELECT SELECT
c.id, c.id,
c.user_id, c.user_id,
@@ -40,7 +40,7 @@ echo "<tr>
<th>Fecha</th> <th>Fecha</th>
</tr>"; </tr>";
foreach ($messages as $msg) { foreach ($conversations as $msg) {
echo "<tr>"; echo "<tr>";
echo "<td>{$msg['id']}</td>"; echo "<td>{$msg['id']}</td>";
echo "<td>{$msg['phone_number']}</td>"; echo "<td>{$msg['phone_number']}</td>";
+3 -3
View File
@@ -17,9 +17,9 @@ try {
ORDER BY created_at DESC LIMIT 5" ORDER BY created_at DESC LIMIT 5"
); );
$messages = $stmt->fetchAll(); $conversations = $stmt->fetchAll();
if ($messages) { if ($conversations) {
foreach ($messages as $msg) { foreach ($conversations as $msg) {
echo "ID: {$msg['id']}, Contenido: {$msg['content']}, Fecha: {$msg['created_at']}\n"; echo "ID: {$msg['id']}, Contenido: {$msg['content']}, Fecha: {$msg['created_at']}\n";
} }
} else { } else {
+1 -1
View File
@@ -151,7 +151,7 @@ if (defined('DB_HOST') && defined('DB_NAME')) {
echo "<div class='ok'>✅ Conexión a base de datos exitosa</div>"; echo "<div class='ok'>✅ Conexión a base de datos exitosa</div>";
// Verificar tablas principales // Verificar tablas principales
$tables = ['conversations', 'messages', 'settings']; $tables = ['conversations', 'conversations', 'system_config'];
foreach ($tables as $table) { foreach ($tables as $table) {
$stmt = $pdo->query("SHOW TABLES LIKE '$table'"); $stmt = $pdo->query("SHOW TABLES LIKE '$table'");
if ($stmt->rowCount() > 0) { if ($stmt->rowCount() > 0) {
+1 -1
View File
@@ -20,7 +20,7 @@ try {
echo "✅ Conexión exitosa<br>"; echo "✅ Conexión exitosa<br>";
// Verificar tablas // Verificar tablas
$tables = ['users', 'conversations', 'messages']; $tables = ['users', 'conversations', 'conversations'];
foreach ($tables as $table) { foreach ($tables as $table) {
try { try {
$stmt = $db->query("SHOW TABLES LIKE '$table'"); $stmt = $db->query("SHOW TABLES LIKE '$table'");
+1 -1
View File
@@ -248,7 +248,7 @@ echo "</div>";
echo "<div class='card'> echo "<div class='card'>
<h2>🛠️ Acciones Rápidas</h2> <h2>🛠️ Acciones Rápidas</h2>
<div style='display: flex; gap: 10px; flex-wrap: wrap;'> <div style='display: flex; gap: 10px; flex-wrap: wrap;'>
<a href='index.php#settings' style='padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px;'>⚙️ Ir a Configuración</a> <a href='index.php#system_config' style='padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px;'>⚙️ Ir a Configuración</a>
<a href='configurar_whatsapp.php' style='padding: 10px 20px; background: #28a745; color: white; text-decoration: none; border-radius: 5px;'>📱 Configurar WhatsApp</a> <a href='configurar_whatsapp.php' style='padding: 10px 20px; background: #28a745; color: white; text-decoration: none; border-radius: 5px;'>📱 Configurar WhatsApp</a>
<a href='test_whatsapp_completo.php' style='padding: 10px 20px; background: #17a2b8; color: white; text-decoration: none; border-radius: 5px;'>🧪 Probar API</a> <a href='test_whatsapp_completo.php' style='padding: 10px 20px; background: #17a2b8; color: white; text-decoration: none; border-radius: 5px;'>🧪 Probar API</a>
</div> </div>
+11 -11
View File
@@ -52,10 +52,10 @@ try {
<li><a href="#conversations" class="nav-link" data-tab="conversations"><i class="fas fa-comments"></i> Conversaciones</a></li> <li><a href="#conversations" class="nav-link" data-tab="conversations"><i class="fas fa-comments"></i> Conversaciones</a></li>
<li><a href="#users" class="nav-link" data-tab="users"><i class="fas fa-users"></i> Usuarios</a></li> <li><a href="#users" class="nav-link" data-tab="users"><i class="fas fa-users"></i> Usuarios</a></li>
<li><a href="#menus" class="nav-link" data-tab="menus"><i class="fas fa-list"></i> Menús</a></li> <li><a href="#menus" class="nav-link" data-tab="menus"><i class="fas fa-list"></i> Menús</a></li>
<li><a href="#messages" class="nav-link" data-tab="messages"><i class="fas fa-paper-plane"></i> Enviar Mensaje</a></li> <li><a href="#conversations" class="nav-link" data-tab="conversations"><i class="fas fa-paper-plane"></i> Enviar Mensaje</a></li>
<li><a href="#templates" class="nav-link" data-tab="templates"><i class="fas fa-file-text"></i> Plantillas</a></li> <li><a href="#templates" class="nav-link" data-tab="templates"><i class="fas fa-file-text"></i> Plantillas</a></li>
<li><a href="#autoresponses" class="nav-link" data-tab="autoresponses"><i class="fas fa-robot"></i> Respuestas Auto</a></li> <li><a href="#autoresponses" class="nav-link" data-tab="autoresponses"><i class="fas fa-robot"></i> Respuestas Auto</a></li>
<li><a href="#settings" class="nav-link" data-tab="settings"><i class="fas fa-cog"></i> Configuración</a></li> <li><a href="#system_config" class="nav-link" data-tab="system_config"><i class="fas fa-cog"></i> Configuración</a></li>
<li><a href="#logs" class="nav-link" data-tab="logs"><i class="fas fa-file-alt"></i> Logs</a></li> <li><a href="#logs" class="nav-link" data-tab="logs"><i class="fas fa-file-alt"></i> Logs</a></li>
<li class="sidebar-divider"></li> <li class="sidebar-divider"></li>
<li><a href="logout.php" class="nav-link logout-link" onclick="return confirm('¿Está seguro que desea cerrar sesión?')"><i class="fas fa-sign-out-alt"></i> Cerrar Sesión</a></li> <li><a href="logout.php" class="nav-link logout-link" onclick="return confirm('¿Está seguro que desea cerrar sesión?')"><i class="fas fa-sign-out-alt"></i> Cerrar Sesión</a></li>
@@ -112,7 +112,7 @@ try {
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col"> <div class="col">
<h6 class="card-stat-title">Mensajes Hoy</h6> <h6 class="card-stat-title">Mensajes Hoy</h6>
<h3 class="card-stat-number" id="messages-today">-</h3> <h3 class="card-stat-number" id="conversations-today">-</h3>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-comment fa-2x"></i> <i class="fas fa-comment fa-2x"></i>
@@ -144,7 +144,7 @@ try {
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col"> <div class="col">
<h6 class="card-stat-title">Total Mensajes</h6> <h6 class="card-stat-title">Total Mensajes</h6>
<h3 class="card-stat-number" id="total-messages">-</h3> <h3 class="card-stat-number" id="total-conversations">-</h3>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-envelope fa-2x"></i> <i class="fas fa-envelope fa-2x"></i>
@@ -163,7 +163,7 @@ try {
<h5><i class="fas fa-chart-line"></i> Actividad Reciente</h5> <h5><i class="fas fa-chart-line"></i> Actividad Reciente</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<canvas id="messagesChart" height="100"></canvas> <canvas id="conversationsChart" height="100"></canvas>
</div> </div>
</div> </div>
</div> </div>
@@ -173,7 +173,7 @@ try {
<h5><i class="fas fa-clock"></i> Últimos Mensajes</h5> <h5><i class="fas fa-clock"></i> Últimos Mensajes</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<div id="recent-messages" class="list-group"> <div id="recent-conversations" class="list-group">
<!-- Contenido dinámico --> <!-- Contenido dinámico -->
</div> </div>
</div> </div>
@@ -275,8 +275,8 @@ try {
</div> </div>
</div> </div>
<!-- Messages Tab --> <!-- conversations Tab -->
<div id="messages" class="tab-content"> <div id="conversations" class="tab-content">
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
@@ -423,8 +423,8 @@ try {
</div> </div>
</div> </div>
<!-- Settings Tab --> <!-- system_config Tab -->
<div id="settings" class="tab-content"> <div id="system_config" class="tab-content">
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-lg-8">
<div class="card"> <div class="card">
@@ -432,7 +432,7 @@ try {
<h5><i class="fas fa-cog"></i> Configuración del Sistema</h5> <h5><i class="fas fa-cog"></i> Configuración del Sistema</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="settings-form"> <form id="system_config-form">
<div class="mb-4"> <div class="mb-4">
<h6 class="text-muted">WhatsApp Business API</h6> <h6 class="text-muted">WhatsApp Business API</h6>
<div class="mb-3"> <div class="mb-3">
+6 -6
View File
@@ -49,7 +49,7 @@ $currentUser = $_SESSION['admin_username'] ?? 'admin';
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-tab="settings" href="#"> <a class="nav-link" data-tab="system_config" href="#">
⚙️ Configuraciones ⚙️ Configuraciones
</a> </a>
</li> </li>
@@ -84,7 +84,7 @@ $currentUser = $_SESSION['admin_username'] ?? 'admin';
<div class="col-md-3"> <div class="col-md-3">
<div class="card text-center"> <div class="card text-center">
<div class="card-body"> <div class="card-body">
<h5 id="messages-today" class="text-success">--</h5> <h5 id="conversations-today" class="text-success">--</h5>
<p class="card-text">WhatsApp</p> <p class="card-text">WhatsApp</p>
</div> </div>
</div> </div>
@@ -100,7 +100,7 @@ $currentUser = $_SESSION['admin_username'] ?? 'admin';
<div class="col-md-3"> <div class="col-md-3">
<div class="card text-center"> <div class="card text-center">
<div class="card-body"> <div class="card-body">
<h5 id="total-messages" class="text-warning">--</h5> <h5 id="total-conversations" class="text-warning">--</h5>
<p class="card-text">Instalación</p> <p class="card-text">Instalación</p>
</div> </div>
</div> </div>
@@ -149,8 +149,8 @@ $currentUser = $_SESSION['admin_username'] ?? 'admin';
</div> </div>
</div> </div>
<!-- Settings Tab --> <!-- system_config Tab -->
<div id="settings" class="tab-content"> <div id="system_config" class="tab-content">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h2>⚙️ Configuraciones</h2> <h2>⚙️ Configuraciones</h2>
</div> </div>
@@ -160,7 +160,7 @@ $currentUser = $_SESSION['admin_username'] ?? 'admin';
<h5>📱 Configuración WhatsApp</h5> <h5>📱 Configuración WhatsApp</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="settings-form"> <form id="system_config-form">
<div class="mb-3"> <div class="mb-3">
<label for="whatsapp_token" class="form-label">Token de WhatsApp</label> <label for="whatsapp_token" class="form-label">Token de WhatsApp</label>
<input type="text" class="form-control" id="whatsapp_token" name="whatsapp_token" <input type="text" class="form-control" id="whatsapp_token" name="whatsapp_token"
+15 -15
View File
@@ -115,10 +115,10 @@ echo "</div>";
echo "<div class='section'>"; echo "<div class='section'>";
echo "<h2>🔧 CREANDO TABLAS FALTANTES...</h2>"; echo "<h2>🔧 CREANDO TABLAS FALTANTES...</h2>";
// Crear tabla 'messages' como alias de conversations // Crear tabla 'conversations' como alias de conversations
try { try {
$pdo->exec(" $pdo->exec("
CREATE TABLE IF NOT EXISTS messages ( CREATE TABLE IF NOT EXISTS conversations (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL, user_id INT NOT NULL,
phone_number VARCHAR(20) NOT NULL, phone_number VARCHAR(20) NOT NULL,
@@ -132,19 +132,19 @@ try {
INDEX idx_created (created_at) INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
"); ");
echo "<div class='ok'>✅ Tabla 'messages' creada</div>"; echo "<div class='ok'>✅ Tabla 'conversations' creada</div>";
} catch (PDOException $e) { } catch (PDOException $e) {
if (strpos($e->getMessage(), 'already exists') === false) { if (strpos($e->getMessage(), 'already exists') === false) {
echo "<div class='error'>❌ Error creando tabla messages: " . htmlspecialchars($e->getMessage()) . "</div>"; echo "<div class='error'>❌ Error creando tabla conversations: " . htmlspecialchars($e->getMessage()) . "</div>";
} else { } else {
echo "<div class='warning'>⚠️ Tabla 'messages' ya existe</div>"; echo "<div class='warning'>⚠️ Tabla 'conversations' ya existe</div>";
} }
} }
// Crear tabla 'settings' como alias de system_config // Crear tabla 'system_config' como alias de system_config
try { try {
$pdo->exec(" $pdo->exec("
CREATE TABLE IF NOT EXISTS settings ( CREATE TABLE IF NOT EXISTS system_config (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
setting_key VARCHAR(100) UNIQUE NOT NULL, setting_key VARCHAR(100) UNIQUE NOT NULL,
setting_value TEXT, setting_value TEXT,
@@ -153,25 +153,25 @@ try {
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
"); ");
echo "<div class='ok'>✅ Tabla 'settings' creada</div>"; echo "<div class='ok'>✅ Tabla 'system_config' creada</div>";
} catch (PDOException $e) { } catch (PDOException $e) {
if (strpos($e->getMessage(), 'already exists') === false) { if (strpos($e->getMessage(), 'already exists') === false) {
echo "<div class='error'>❌ Error creando tabla settings: " . htmlspecialchars($e->getMessage()) . "</div>"; echo "<div class='error'>❌ Error creando tabla system_config: " . htmlspecialchars($e->getMessage()) . "</div>";
} else { } else {
echo "<div class='warning'>⚠️ Tabla 'settings' ya existe</div>"; echo "<div class='warning'>⚠️ Tabla 'system_config' ya existe</div>";
} }
} }
echo "</div>"; echo "</div>";
// Copiar datos de system_config a settings si no existen // Copiar datos de system_config a system_config si no existen
echo "<div class='section'>"; echo "<div class='section'>";
echo "<h2>📊 SINCRONIZANDO CONFIGURACIÓN...</h2>"; echo "<h2>📊 SINCRONIZANDO CONFIGURACIÓN...</h2>";
try { try {
// Copiar datos de system_config a settings // Copiar datos de system_config a system_config
$pdo->exec(" $pdo->exec("
INSERT IGNORE INTO settings (setting_key, setting_value, description, created_at) INSERT IGNORE INTO system_config (setting_key, setting_value, description, created_at)
SELECT config_key, config_value, description, created_at SELECT config_key, config_value, description, created_at
FROM system_config FROM system_config
WHERE config_key IS NOT NULL WHERE config_key IS NOT NULL
@@ -188,7 +188,7 @@ try {
try { try {
if (!defined('SECRET_KEY') || empty(SECRET_KEY)) { if (!defined('SECRET_KEY') || empty(SECRET_KEY)) {
$secret_key = bin2hex(random_bytes(32)); $secret_key = bin2hex(random_bytes(32));
$pdo->prepare("INSERT INTO settings (setting_key, setting_value, description) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)") $pdo->prepare("INSERT INTO system_config (setting_key, setting_value, description) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)")
->execute(['SECRET_KEY', $secret_key, 'Clave secreta para encriptación']); ->execute(['SECRET_KEY', $secret_key, 'Clave secreta para encriptación']);
echo "<div class='ok'>✅ SECRET_KEY generada y guardada</div>"; echo "<div class='ok'>✅ SECRET_KEY generada y guardada</div>";
echo "<div class='warning'>🔑 IMPORTANTE: Agrega esta línea a config/config.php:</div>"; echo "<div class='warning'>🔑 IMPORTANTE: Agrega esta línea a config/config.php:</div>";
@@ -204,7 +204,7 @@ echo "</div>";
echo "<div class='section'>"; echo "<div class='section'>";
echo "<h2>✅ VERIFICACIÓN FINAL</h2>"; echo "<h2>✅ VERIFICACIÓN FINAL</h2>";
$required_tables = ['conversations', 'messages', 'settings', 'message_templates', 'users', 'menus']; $required_tables = ['conversations', 'conversations', 'system_config', 'message_templates', 'users', 'menus'];
$missing_tables = []; $missing_tables = [];
foreach ($required_tables as $table) { foreach ($required_tables as $table) {
+2 -2
View File
@@ -93,7 +93,7 @@ $integratedSchema = [
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)", )",
"CREATE TABLE IF NOT EXISTS auto_responses ( "CREATE TABLE IF NOT EXISTS autoresponses (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
trigger_type ENUM('keyword', 'menu_selection', 'welcome') NOT NULL, trigger_type ENUM('keyword', 'menu_selection', 'welcome') NOT NULL,
trigger_value VARCHAR(200), trigger_value VARCHAR(200),
@@ -136,7 +136,7 @@ $initialData = [
(1, 0, '❌ Salir', 'end', 'Gracias por contactarnos. ¡Hasta pronto!')", (1, 0, '❌ Salir', 'end', 'Gracias por contactarnos. ¡Hasta pronto!')",
// Respuestas automáticas // Respuestas automáticas
"INSERT IGNORE INTO auto_responses (trigger_type, trigger_value, response_text) VALUES "INSERT IGNORE INTO autoresponses (trigger_type, trigger_value, response_text) VALUES
('keyword', 'menu', 'Aquí tienes nuestro menú principal:'), ('keyword', 'menu', 'Aquí tienes nuestro menú principal:'),
('keyword', 'hola', '¡Hola! 👋 Escribe *menu* para ver opciones.'), ('keyword', 'hola', '¡Hola! 👋 Escribe *menu* para ver opciones.'),
('welcome', '', '¡Bienvenido! 👋 Escribe *menu* para comenzar.')" ('welcome', '', '¡Bienvenido! 👋 Escribe *menu* para comenzar.')"
+2 -2
View File
@@ -242,7 +242,7 @@ if ($_POST && !$loginBlocked) {
</div> </div>
</div> </div>
<!-- Success Messages --> <!-- Success conversations -->
<?php if ($success): ?> <?php if ($success): ?>
<div class="alert alert-success"> <div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i> <i class="fas fa-check-circle me-2"></i>
@@ -250,7 +250,7 @@ if ($_POST && !$loginBlocked) {
</div> </div>
<?php endif; ?> <?php endif; ?>
<!-- Error Messages --> <!-- Error conversations -->
<?php if ($error && !$loginBlocked): ?> <?php if ($error && !$loginBlocked): ?>
<div class="alert alert-danger"> <div class="alert alert-danger">
<i class="fas fa-exclamation-triangle me-2"></i> <i class="fas fa-exclamation-triangle me-2"></i>
+4 -4
View File
@@ -14,8 +14,8 @@ try {
if (!empty($entry['changes'])) { if (!empty($entry['changes'])) {
foreach ($entry['changes'] as $change) { foreach ($entry['changes'] as $change) {
$val = $change['value'] ?? []; $val = $change['value'] ?? [];
if (!empty($val['messages'])) { if (!empty($val['conversations'])) {
foreach ($val['messages'] as $m) { foreach ($val['conversations'] as $m) {
$mid = $m['id'] ?? null; $mid = $m['id'] ?? null;
$from = $m['from'] ?? null; $from = $m['from'] ?? null;
if ($mid) { if ($mid) {
@@ -33,9 +33,9 @@ try {
} }
if (empty($missing)) { if (empty($missing)) {
echo "All recent messages found in conversations.\n"; echo "All recent conversations found in conversations.\n";
} else { } else {
echo "Missing messages (not found in conversations):\n"; echo "Missing conversations (not found in conversations):\n";
foreach ($missing as $m) { foreach ($missing as $m) {
echo json_encode($m) . PHP_EOL; echo json_encode($m) . PHP_EOL;
} }
+1 -1
View File
@@ -6,7 +6,7 @@ try {
$rows = $db->fetchAll('SELECT id, request_body, created_at FROM webhook_logs ORDER BY created_at DESC LIMIT 20'); $rows = $db->fetchAll('SELECT id, request_body, created_at FROM webhook_logs ORDER BY created_at DESC LIMIT 20');
foreach ($rows as $r) { foreach ($rows as $r) {
$rb = $r['request_body']; $rb = $r['request_body'];
$has = strpos($rb, '"messages"') !== false ? 'HAS_MESSAGES' : (strpos($rb, '"statuses"') !== false ? 'ONLY_STATUSES' : 'OTHER'); $has = strpos($rb, '"conversations"') !== false ? 'HAS_conversations' : (strpos($rb, '"statuses"') !== false ? 'ONLY_STATUSES' : 'OTHER');
echo $r['created_at'] . ' | id:' . $r['id'] . ' | ' . $has . PHP_EOL; echo $r['created_at'] . ' | id:' . $r['id'] . ' | ' . $has . PHP_EOL;
} }
} catch (Exception $e) { } catch (Exception $e) {
+2 -2
View File
@@ -12,8 +12,8 @@ try {
foreach ($payload['entry'] as $entry) { foreach ($payload['entry'] as $entry) {
foreach ($entry['changes'] as $change) { foreach ($entry['changes'] as $change) {
$val = $change['value']; $val = $change['value'];
if (!empty($val['messages'])) { if (!empty($val['conversations'])) {
foreach ($val['messages'] as $message) { foreach ($val['conversations'] as $message) {
$phone = $message['from']; $phone = $message['from'];
$mid = $message['id']; $mid = $message['id'];
$text = $message['text']['body'] ?? ''; $text = $message['text']['body'] ?? '';
+2 -2
View File
@@ -9,9 +9,9 @@ $payload = [
[ [
'changes' => [ 'changes' => [
[ [
'field' => 'messages', 'field' => 'conversations',
'value' => [ 'value' => [
'messages' => [ 'conversations' => [
[ [
'from' => '573019999900', 'from' => '573019999900',
'id' => 'NTFTEST1', 'id' => 'NTFTEST1',
+4 -4
View File
@@ -27,7 +27,7 @@ $payload = [
[ [
'changes' => [ 'changes' => [
[ [
'field' => 'messages', 'field' => 'conversations',
'value' => [ 'value' => [
'messaging_product' => 'whatsapp', 'messaging_product' => 'whatsapp',
'metadata' => [ 'metadata' => [
@@ -37,7 +37,7 @@ $payload = [
'contacts' => [ 'contacts' => [
[ 'profile' => ['name' => 'reactor'], 'wa_id' => $testPhone ] [ 'profile' => ['name' => 'reactor'], 'wa_id' => $testPhone ]
], ],
'messages' => [ 'conversations' => [
[ [
'from' => $testPhone, 'from' => $testPhone,
'id' => '2001', 'id' => '2001',
@@ -86,9 +86,9 @@ $payload2 = [
[ [
'changes' => [ 'changes' => [
[ [
'field' => 'messages', 'field' => 'conversations',
'value' => [ 'value' => [
'messages' => [ 'conversations' => [
[ [
'from' => $testPhone2, 'from' => $testPhone2,
'id' => '2002', 'id' => '2002',
+1 -1
View File
@@ -1 +1 @@
{"object":"whatsapp_business_account","entry":[{"id":"0","changes":[{"field":"messages","value":{"messaging_product":"whatsapp","metadata":{"display_phone_number":"16505551111","phone_number_id":"123456123"},"contacts":[{"profile":{"name":"test user name"},"wa_id":"16315551181"}],"messages":[{"from":"16315551181","id":"ABGGFlA5Fpa","timestamp":"1504902988","type":"text","text":{"body":"this is a text message"}}]}}]}]} {"object":"whatsapp_business_account","entry":[{"id":"0","changes":[{"field":"conversations","value":{"messaging_product":"whatsapp","metadata":{"display_phone_number":"16505551111","phone_number_id":"123456123"},"contacts":[{"profile":{"name":"test user name"},"wa_id":"16315551181"}],"conversations":[{"from":"16315551181","id":"ABGGFlA5Fpa","timestamp":"1504902988","type":"text","text":{"body":"this is a text message"}}]}}]}]}
+4 -4
View File
@@ -11,7 +11,7 @@ $payload = [
"id" => "0", "id" => "0",
"changes" => [ "changes" => [
[ [
"field" => "messages", "field" => "conversations",
"value" => [ "value" => [
"messaging_product" => "whatsapp", "messaging_product" => "whatsapp",
"metadata" => [ "metadata" => [
@@ -24,7 +24,7 @@ $payload = [
"wa_id" => "16315551181" "wa_id" => "16315551181"
] ]
], ],
"messages" => [ "conversations" => [
[ [
"from" => "16315551181", "from" => "16315551181",
"id" => "ABGGFlA5Fpa", "id" => "ABGGFlA5Fpa",
@@ -54,7 +54,7 @@ try {
"id" => "0", "id" => "0",
"changes" => [ "changes" => [
[ [
"field" => "messages", "field" => "conversations",
"value" => [ "value" => [
"messaging_product" => "whatsapp", "messaging_product" => "whatsapp",
"metadata" => [ "metadata" => [
@@ -67,7 +67,7 @@ try {
"wa_id" => "16315551181" "wa_id" => "16315551181"
] ]
], ],
"messages" => [ "conversations" => [
[ [
"from" => "16315551181", "from" => "16315551181",
"id" => "REACTION1", "id" => "REACTION1",
+1 -1
View File
@@ -262,7 +262,7 @@ $step = $_GET['step'] ?? 'welcome';
<ul class="mt-2 mb-0"> <ul class="mt-2 mb-0">
<li><strong>Webhook URL:</strong> https://<?= htmlspecialchars($domain) ?>/bot/api/webhook.php</li> <li><strong>Webhook URL:</strong> https://<?= htmlspecialchars($domain) ?>/bot/api/webhook.php</li>
<li><strong>Verify Token:</strong> <?= htmlspecialchars($webhook_token) ?></li> <li><strong>Verify Token:</strong> <?= htmlspecialchars($webhook_token) ?></li>
<li><strong>Subscribe to:</strong> messages</li> <li><strong>Subscribe to:</strong> conversations</li>
</ul> </ul>
</div> </div>
+2 -2
View File
@@ -442,12 +442,12 @@ class BotService {
)['count']; )['count'];
// Total de mensajes // Total de mensajes
$stats['total_messages'] = $this->db->fetch( $stats['total_conversations'] = $this->db->fetch(
"SELECT COUNT(*) as count FROM conversations" "SELECT COUNT(*) as count FROM conversations"
)['count']; )['count'];
// Mensajes hoy // Mensajes hoy
$stats['messages_today'] = $this->db->fetch( $stats['conversations_today'] = $this->db->fetch(
"SELECT COUNT(*) as count FROM conversations "SELECT COUNT(*) as count FROM conversations
WHERE DATE(created_at) = CURDATE()" WHERE DATE(created_at) = CURDATE()"
)['count']; )['count'];
+4 -4
View File
@@ -233,7 +233,7 @@ class WhatsAppService
'message_id' => $messageId 'message_id' => $messageId
]; ];
$url = $this->apiUrl . $this->phoneNumberId . '/messages'; $url = $this->apiUrl . $this->phoneNumberId . '/conversations';
return $this->makeRequest('POST', $url, $data); return $this->makeRequest('POST', $url, $data);
} }
@@ -400,7 +400,7 @@ class WhatsAppService
private function sendMessage($data) private function sendMessage($data)
{ {
// Construir URL correctamente // Construir URL correctamente
$url = rtrim($this->apiUrl, '/') . '/' . $this->phoneNumberId . '/messages'; $url = rtrim($this->apiUrl, '/') . '/' . $this->phoneNumberId . '/conversations';
// Debug log // Debug log
error_log("WhatsApp API URL: " . $url); error_log("WhatsApp API URL: " . $url);
@@ -410,7 +410,7 @@ class WhatsAppService
$response = $this->makeRequest('POST', $url, $data); $response = $this->makeRequest('POST', $url, $data);
// Guardar mensaje enviado en la base de datos // Guardar mensaje enviado en la base de datos
if ($response && isset($response['messages'][0]['id'])) { if ($response && isset($response['conversations'][0]['id'])) {
$this->saveOutgoingMessage($data, $response); $this->saveOutgoingMessage($data, $response);
} }
@@ -506,7 +506,7 @@ class WhatsAppService
if ($user) { if ($user) {
$messageData = [ $messageData = [
'user_id' => $user['id'], 'user_id' => $user['id'],
'message_id' => $response['messages'][0]['id'], 'message_id' => $response['conversations'][0]['id'],
'direction' => 'outgoing', 'direction' => 'outgoing',
'message_type' => $data['type'], 'message_type' => $data['type'],
'content' => $this->extractMessageContent($data), 'content' => $this->extractMessageContent($data),
+1 -1
View File
@@ -108,7 +108,7 @@ header('Content-Type: text/html; charset=utf-8');
$tablesDetails = ''; $tablesDetails = '';
if ($dbOk) { if ($dbOk) {
try { try {
$requiredTables = ['users', 'conversations', 'menus', 'menu_options', 'auto_responses', 'system_config']; $requiredTables = ['users', 'conversations', 'menus', 'menu_options', 'autoresponses', 'system_config'];
$db = Database::getInstance(); $db = Database::getInstance();
$existingTables = []; $existingTables = [];
$missingTables = []; $missingTables = [];
+27 -27
View File
@@ -279,31 +279,31 @@ class APITestSuite {
private function testConfigurationAPIs() { private function testConfigurationAPIs() {
echo "<h4>⚙️ Tests de APIs de Configuración</h4>"; echo "<h4>⚙️ Tests de APIs de Configuración</h4>";
// Test get_settings.php // Test get_system_config.php
$this->apiTest("API get_settings existe", function() { $this->apiTest("API get_system_config existe", function() {
if (!file_exists(__DIR__ . '/../api/get_settings.php')) { if (!file_exists(__DIR__ . '/../api/get_system_config.php')) {
throw new Exception("get_settings.php no existe"); throw new Exception("get_system_config.php no existe");
} }
$content = file_get_contents(__DIR__ . '/../api/get_settings.php'); $content = file_get_contents(__DIR__ . '/../api/get_system_config.php');
if (strpos($content, 'requireAuthentication()') === false) { if (strpos($content, 'requireAuthentication()') === false) {
throw new Exception("get_settings no requiere autenticación"); throw new Exception("get_system_config no requiere autenticación");
} }
return "API get_settings correcta"; return "API get_system_config correcta";
}); });
// Test save_settings.php // Test save_system_config.php
$this->apiTest("API save_settings existe", function() { $this->apiTest("API save_system_config existe", function() {
if (!file_exists(__DIR__ . '/../api/save_settings.php')) { if (!file_exists(__DIR__ . '/../api/save_system_config.php')) {
throw new Exception("save_settings.php no existe"); throw new Exception("save_system_config.php no existe");
} }
$content = file_get_contents(__DIR__ . '/../api/save_settings.php'); $content = file_get_contents(__DIR__ . '/../api/save_system_config.php');
if (strpos($content, 'requireAuthentication()') === false) { if (strpos($content, 'requireAuthentication()') === false) {
throw new Exception("save_settings no requiere autenticación"); throw new Exception("save_system_config no requiere autenticación");
} }
$fields = ['business_name', 'whatsapp_token', 'phone_number_id']; $fields = ['business_name', 'whatsapp_token', 'phone_number_id'];
@@ -313,16 +313,16 @@ class APITestSuite {
} }
} }
return "API save_settings completa"; return "API save_system_config completa";
}); });
// Verificar tabla settings // Verificar tabla system_config
$this->apiTest("Verificar tabla configuración", function() { $this->apiTest("Verificar tabla configuración", function() {
$db = Database::getInstance(); $db = Database::getInstance();
$result = $db->fetchAll("SHOW TABLES LIKE 'settings'"); $result = $db->fetchAll("SHOW TABLES LIKE 'system_config'");
if (!$result || empty($result)) { if (!$result || empty($result)) {
throw new Exception("Tabla settings no existe"); throw new Exception("Tabla system_config no existe");
} }
return "Tabla de configuración existe"; return "Tabla de configuración existe";
@@ -344,7 +344,7 @@ class APITestSuite {
throw new Exception("get_stats no requiere autenticación"); throw new Exception("get_stats no requiere autenticación");
} }
$stats = ['total_users', 'messages_today', 'active_users', 'total_messages']; $stats = ['total_users', 'conversations_today', 'active_users', 'total_conversations'];
foreach ($stats as $stat) { foreach ($stats as $stat) {
if (strpos($content, $stat) === false) { if (strpos($content, $stat) === false) {
throw new Exception("Estadística '$stat' no está implementada"); throw new Exception("Estadística '$stat' no está implementada");
@@ -369,30 +369,30 @@ class APITestSuite {
return "API get_chart_data correcta"; return "API get_chart_data correcta";
}); });
// Test get_recent_messages.php // Test get_recent_conversations.php
$this->apiTest("API get_recent_messages existe", function() { $this->apiTest("API get_recent_conversations existe", function() {
if (!file_exists(__DIR__ . '/../api/get_recent_messages.php')) { if (!file_exists(__DIR__ . '/../api/get_recent_conversations.php')) {
throw new Exception("get_recent_messages.php no existe"); throw new Exception("get_recent_conversations.php no existe");
} }
$content = file_get_contents(__DIR__ . '/../api/get_recent_messages.php'); $content = file_get_contents(__DIR__ . '/../api/get_recent_conversations.php');
if (strpos($content, 'requireAuthentication()') === false) { if (strpos($content, 'requireAuthentication()') === false) {
throw new Exception("get_recent_messages no requiere autenticación"); throw new Exception("get_recent_conversations no requiere autenticación");
} }
if (strpos($content, 'messages') === false && strpos($content, 'conversations') === false) { if (strpos($content, 'conversations') === false && strpos($content, 'conversations') === false) {
throw new Exception("No consulta mensajes"); throw new Exception("No consulta mensajes");
} }
return "API get_recent_messages correcta"; return "API get_recent_conversations correcta";
}); });
// Test de integridad de datos // Test de integridad de datos
$this->apiTest("Verificar tablas de analytics", function() { $this->apiTest("Verificar tablas de analytics", function() {
$db = Database::getInstance(); $db = Database::getInstance();
$tables = ['messages', 'conversations']; $tables = ['conversations', 'conversations'];
foreach ($tables as $table) { foreach ($tables as $table) {
$result = $db->fetchAll("SHOW TABLES LIKE '$table'"); $result = $db->fetchAll("SHOW TABLES LIKE '$table'");
if (!$result || empty($result)) { if (!$result || empty($result)) {
+2 -2
View File
@@ -314,7 +314,7 @@ class TestRunner {
'changes' => [ 'changes' => [
[ [
'value' => [ 'value' => [
'messages' => [ 'conversations' => [
[ [
'from' => '573001234567', 'from' => '573001234567',
'text' => ['body' => 'test message'], 'text' => ['body' => 'test message'],
@@ -442,7 +442,7 @@ class TestRunner {
$db = Database::getInstance(); $db = Database::getInstance();
$requiredTables = [ $requiredTables = [
'users', 'conversations', 'menus', 'menu_options', 'users', 'conversations', 'menus', 'menu_options',
'system_config', 'auto_responses', 'message_templates', 'system_config', 'autoresponses', 'message_templates',
'webhook_logs' 'webhook_logs'
]; ];
+1 -1
View File
@@ -114,7 +114,7 @@ class SecurityTestSuite {
$this->securityTest("APIs requieren autenticación", function() { $this->securityTest("APIs requieren autenticación", function() {
$protectedAPIs = [ $protectedAPIs = [
'get_stats.php', 'get_users.php', 'send_message.php', 'get_stats.php', 'get_users.php', 'send_message.php',
'save_template.php', 'get_templates.php', 'save_settings.php' 'save_template.php', 'get_templates.php', 'save_system_config.php'
]; ];
unset($_SESSION['admin_logged_in']); unset($_SESSION['admin_logged_in']);
+2 -2
View File
@@ -203,7 +203,7 @@ class ServiceTestSuite {
$this->serviceTest("Test de respuestas automáticas", function() { $this->serviceTest("Test de respuestas automáticas", function() {
// Verificar que hay respuestas automáticas configuradas // Verificar que hay respuestas automáticas configuradas
$responses = $this->db->fetchAll( $responses = $this->db->fetchAll(
"SELECT * FROM auto_responses WHERE trigger_type = 'keyword'" "SELECT * FROM autoresponses WHERE trigger_type = 'keyword'"
); );
if (empty($responses)) { if (empty($responses)) {
@@ -216,7 +216,7 @@ class ServiceTestSuite {
foreach ($requiredFields as $field) { foreach ($requiredFields as $field) {
if (!isset($firstResponse[$field])) { if (!isset($firstResponse[$field])) {
throw new Exception("Campo requerido '$field' faltante en auto_responses"); throw new Exception("Campo requerido '$field' faltante en autoresponses");
} }
} }
+8 -8
View File
@@ -159,7 +159,7 @@ class WebhookTestSuite {
'display_phone_number' => '573001234567', 'display_phone_number' => '573001234567',
'phone_number_id' => WHATSAPP_PHONE_NUMBER_ID 'phone_number_id' => WHATSAPP_PHONE_NUMBER_ID
], ],
'messages' => [ 'conversations' => [
[ [
'from' => '573009876543', 'from' => '573009876543',
'id' => 'wamid.test123', 'id' => 'wamid.test123',
@@ -171,7 +171,7 @@ class WebhookTestSuite {
] ]
] ]
], ],
'field' => 'messages' 'field' => 'conversations'
] ]
] ]
] ]
@@ -183,7 +183,7 @@ class WebhookTestSuite {
throw new Exception("Estructura de payload incorrecta"); throw new Exception("Estructura de payload incorrecta");
} }
if (!isset($validPayload['entry'][0]['changes'][0]['value']['messages'])) { if (!isset($validPayload['entry'][0]['changes'][0]['value']['conversations'])) {
throw new Exception("Estructura de mensajes incorrecta"); throw new Exception("Estructura de mensajes incorrecta");
} }
@@ -205,7 +205,7 @@ class WebhookTestSuite {
'changes' => [ 'changes' => [
[ [
'value' => [ 'value' => [
'messages' => [ 'conversations' => [
[ [
'from' => $testPhone, 'from' => $testPhone,
'id' => 'test_message_id', 'id' => 'test_message_id',
@@ -328,9 +328,9 @@ class WebhookTestSuite {
[ [
'changes' => [ 'changes' => [
[ [
'field' => 'messages', 'field' => 'conversations',
'value' => [ 'value' => [
'messages' => [ 'conversations' => [
[ [
'from' => $testPhone, 'from' => $testPhone,
'id' => '2001', 'id' => '2001',
@@ -383,9 +383,9 @@ class WebhookTestSuite {
[ [
'changes' => [ 'changes' => [
[ [
'field' => 'messages', 'field' => 'conversations',
'value' => [ 'value' => [
'messages' => [ 'conversations' => [
[ [
'from' => $testPhone, 'from' => $testPhone,
'id' => '2002', 'id' => '2002',
+2 -2
View File
@@ -21,7 +21,7 @@ $data = [
'type' => 'reaction', 'type' => 'reaction',
'reaction' => ['message_id' => '5001', 'emoji' => '❤️'] 'reaction' => ['message_id' => '5001', 'emoji' => '❤️']
]; ];
$response = ['messages' => [['id' => 'out_msg_1']]]; $response = ['conversations' => [['id' => 'out_msg_1']]];
$foundUser = $db->fetch('SELECT * FROM users WHERE phone_number = :p', ['p' => $phone]); $foundUser = $db->fetch('SELECT * FROM users WHERE phone_number = :p', ['p' => $phone]);
echo "User found for outgoing reaction? " . ($foundUser ? 'yes' : 'no') . "\n"; echo "User found for outgoing reaction? " . ($foundUser ? 'yes' : 'no') . "\n";
@@ -71,7 +71,7 @@ $data2 = [
'context' => ['message_id' => '5002'], 'context' => ['message_id' => '5002'],
'text' => ['body' => 'Gracias'] 'text' => ['body' => 'Gracias']
]; ];
$response2 = ['messages' => [['id' => 'out_msg_2']]]; $response2 = ['conversations' => [['id' => 'out_msg_2']]];
$method->invokeArgs($service, [$data2, $response2]); $method->invokeArgs($service, [$data2, $response2]);
$conv2 = $db->fetch('SELECT * FROM conversations WHERE message_id = :mid', ['mid' => 'out_msg_2']); $conv2 = $db->fetch('SELECT * FROM conversations WHERE message_id = :mid', ['mid' => 'out_msg_2']);
if ($conv2) { if ($conv2) {
+3 -3
View File
@@ -89,7 +89,7 @@ if (defined('DB_HOST') && defined('DB_NAME') && defined('DB_USER') && defined('D
$successes++; $successes++;
// Verificar tablas principales // Verificar tablas principales
$tables = ['conversations', 'messages', 'settings', 'message_templates']; $tables = ['conversations', 'conversations', 'system_config', 'message_templates'];
foreach ($tables as $table) { foreach ($tables as $table) {
$stmt = $pdo->query("SHOW TABLES LIKE '$table'"); $stmt = $pdo->query("SHOW TABLES LIKE '$table'");
if ($stmt->rowCount() > 0) { if ($stmt->rowCount() > 0) {
@@ -135,8 +135,8 @@ echo "<h2>🔌 Verificación de APIs</h2>";
$apis = [ $apis = [
'api/send_message.php', 'api/send_message.php',
'api/webhook.php', 'api/webhook.php',
'api/get_settings.php', 'api/get_system_config.php',
'api/save_settings.php', 'api/save_system_config.php',
'api/get_templates.php' 'api/get_templates.php'
]; ];