uo
This commit is contained in:
+220
-18
@@ -377,6 +377,9 @@ class SimpleWhatsAppManager {
|
|||||||
const container = document.getElementById('users-table');
|
const container = document.getElementById('users-table');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
|
// Guardar datos para uso posterior
|
||||||
|
this.usersData = users;
|
||||||
|
|
||||||
if (users.length === 0) {
|
if (users.length === 0) {
|
||||||
container.innerHTML = '<tr><td colspan="7" class="text-center text-muted">No hay usuarios registrados</td></tr>';
|
container.innerHTML = '<tr><td colspan="7" class="text-center text-muted">No hay usuarios registrados</td></tr>';
|
||||||
return;
|
return;
|
||||||
@@ -834,6 +837,9 @@ class SimpleWhatsAppManager {
|
|||||||
const container = document.getElementById('templates-table');
|
const container = document.getElementById('templates-table');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
|
// Guardar datos para uso posterior
|
||||||
|
this.templatesData = templates;
|
||||||
|
|
||||||
if (templates.length === 0) {
|
if (templates.length === 0) {
|
||||||
container.innerHTML = '<tr><td colspan="6" class="text-center text-muted">No hay plantillas registradas</td></tr>';
|
container.innerHTML = '<tr><td colspan="6" class="text-center text-muted">No hay plantillas registradas</td></tr>';
|
||||||
return;
|
return;
|
||||||
@@ -1100,14 +1106,24 @@ class SimpleWhatsAppManager {
|
|||||||
this.log('Guardando respuesta automática');
|
this.log('Guardando respuesta automática');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const autoresponseId = document.getElementById('autoresponse-id')?.value || '';
|
||||||
|
|
||||||
const responseData = {
|
const responseData = {
|
||||||
trigger_type: document.getElementById('autoresponse-type')?.value || 'keyword',
|
trigger_type: document.getElementById('autoresponse-trigger-type')?.value || 'keyword',
|
||||||
trigger_value: document.getElementById('autoresponse-trigger')?.value || '',
|
trigger_value: document.getElementById('autoresponse-trigger-value')?.value || '',
|
||||||
response_text: document.getElementById('autoresponse-text')?.value || '',
|
response_text: document.getElementById('autoresponse-text')?.value || '',
|
||||||
response_type: document.getElementById('autoresponse-response-type')?.value || 'text',
|
response_type: document.getElementById('autoresponse-type')?.value || 'text',
|
||||||
is_active: document.getElementById('autoresponse-active')?.checked ? 1 : 0
|
priority: document.getElementById('autoresponse-priority')?.value || 0,
|
||||||
|
template_name: document.getElementById('autoresponse-template-name')?.value || '',
|
||||||
|
menu_id: document.getElementById('autoresponse-menu-id')?.value || '',
|
||||||
|
is_active: document.getElementById('autoresponse-active')?.value === '1' ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Si hay ID, es una actualización
|
||||||
|
if (autoresponseId) {
|
||||||
|
responseData.id = autoresponseId;
|
||||||
|
}
|
||||||
|
|
||||||
// Validar campos requeridos
|
// Validar campos requeridos
|
||||||
if (!responseData.response_text) {
|
if (!responseData.response_text) {
|
||||||
this.showError('El texto de respuesta es requerido');
|
this.showError('El texto de respuesta es requerido');
|
||||||
@@ -1157,7 +1173,7 @@ class SimpleWhatsAppManager {
|
|||||||
try {
|
try {
|
||||||
const response = await this.apiCall('delete_autoresponse.php', {
|
const response = await this.apiCall('delete_autoresponse.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: { response_id: responseId }
|
body: { id: responseId }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response && response.success) {
|
if (response && response.success) {
|
||||||
@@ -1440,6 +1456,50 @@ class SimpleWhatsAppManager {
|
|||||||
const bootstrapModal = new bootstrap.Modal(modal);
|
const bootstrapModal = new bootstrap.Modal(modal);
|
||||||
bootstrapModal.show();
|
bootstrapModal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteUserAction(userId, userName, userPhone) {
|
||||||
|
if (!confirm(`¿Estás seguro de que quieres eliminar este usuario?\n\nUsuario: ${userName}\nTeléfono: ${userPhone}\n\nEsta acción no se puede deshacer y eliminará:\n• Todos sus mensajes\n• Su historial de conversación\n• Sus datos personales`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log(`Eliminando usuario ID: ${userId}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.apiCall('delete_user.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { id: userId }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response && response.success) {
|
||||||
|
this.showSuccess('Usuario eliminado correctamente');
|
||||||
|
this.loadUsers(); // Recargar la lista
|
||||||
|
} else {
|
||||||
|
this.showError(`Error eliminando usuario: ${response?.error || 'Error desconocido'}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.showError('Error eliminando usuario: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteTemplateAction(templateId) {
|
||||||
|
this.log(`Eliminando plantilla ID: ${templateId}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.apiCall('delete_template.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { id: templateId }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response && response.success) {
|
||||||
|
this.showSuccess('Plantilla eliminada correctamente');
|
||||||
|
this.loadTemplates(); // Recargar la lista
|
||||||
|
} else {
|
||||||
|
this.showError(`Error eliminando plantilla: ${response?.error || 'Error desconocido'}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.showError('Error eliminando plantilla: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inicializar cuando el DOM esté listo
|
// Inicializar cuando el DOM esté listo
|
||||||
@@ -1987,7 +2047,18 @@ window.viewConversation = function (userId) {
|
|||||||
// Función para editar usuario
|
// Función para editar usuario
|
||||||
window.editUser = function (userId) {
|
window.editUser = function (userId) {
|
||||||
console.log('Editando usuario:', userId);
|
console.log('Editando usuario:', userId);
|
||||||
alert(`Editar usuario ${userId} - Función en desarrollo`);
|
|
||||||
|
// Buscar el usuario en los datos cargados
|
||||||
|
if (window.whatsappManager && window.whatsappManager.usersData) {
|
||||||
|
const user = window.whatsappManager.usersData.find(u => u.id == userId);
|
||||||
|
if (user) {
|
||||||
|
showEditUserModal(user);
|
||||||
|
} else {
|
||||||
|
alert('Error: Usuario no encontrado');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert('Error: Datos no disponibles, recarga la página');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para ver historial de usuario
|
// Función para ver historial de usuario
|
||||||
@@ -2009,8 +2080,11 @@ window.viewUserHistory = function (userId) {
|
|||||||
<div class="text-center py-4">
|
<div class="text-center py-4">
|
||||||
<i class="fas fa-history fa-3x text-muted mb-3"></i>
|
<i class="fas fa-history fa-3x text-muted mb-3"></i>
|
||||||
<h5>Historial de Usuario</h5>
|
<h5>Historial de Usuario</h5>
|
||||||
<p class="text-muted">Esta funcionalidad está en desarrollo.<br>
|
<p class="text-muted">Para ver el historial completo de conversaciones, usa la pestaña <strong>"Conversaciones"</strong> en el menú principal.<br>
|
||||||
Aquí se mostrará el historial completo de mensajes y actividades del usuario.</p>
|
Allí podrás ver todos los mensajes y el historial detallado de cada usuario.</p>
|
||||||
|
<a href="#" onclick="window.whatsappManager.showTab('conversations'); bootstrap.Modal.getInstance(document.getElementById('userHistoryModal')).hide(); return false;" class="btn btn-primary mt-3">
|
||||||
|
<i class="fas fa-comments"></i> Ir a Conversaciones
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@@ -2074,8 +2148,21 @@ window.deleteUser = async function (userId) {
|
|||||||
// Función para eliminar usuario
|
// Función para eliminar usuario
|
||||||
window.deleteUser = function (userId) {
|
window.deleteUser = function (userId) {
|
||||||
console.log('Eliminando usuario:', userId);
|
console.log('Eliminando usuario:', userId);
|
||||||
if (confirm(`¿Está seguro que desea eliminar el usuario ${userId}?`)) {
|
|
||||||
alert(`Eliminar usuario ${userId} - Función en desarrollo`);
|
// Buscar el usuario para mostrar información
|
||||||
|
let userName = 'Usuario ' + userId;
|
||||||
|
let userPhone = '';
|
||||||
|
|
||||||
|
if (window.whatsappManager && window.whatsappManager.usersData) {
|
||||||
|
const user = window.whatsappManager.usersData.find(u => u.id == userId);
|
||||||
|
if (user) {
|
||||||
|
userName = user.name || 'Usuario ' + userId;
|
||||||
|
userPhone = user.phone_number || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.whatsappManager) {
|
||||||
|
window.whatsappManager.deleteUserAction(userId, userName, userPhone);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2087,13 +2174,132 @@ window.showCreateTemplateModal = function () {
|
|||||||
|
|
||||||
window.editTemplate = function (templateId) {
|
window.editTemplate = function (templateId) {
|
||||||
console.log('Editando plantilla:', templateId);
|
console.log('Editando plantilla:', templateId);
|
||||||
alert(`Editar plantilla ${templateId} - Función en desarrollo`);
|
|
||||||
|
// Las plantillas de WhatsApp no se pueden editar una vez creadas
|
||||||
|
// Solo se pueden crear nuevas o eliminar existentes
|
||||||
|
if (window.whatsappManager) {
|
||||||
|
window.whatsappManager.showInfo(
|
||||||
|
'Las plantillas de WhatsApp aprobadas no se pueden editar una vez creadas. ' +
|
||||||
|
'Si necesitas cambiar el contenido, debes crear una nueva plantilla y enviarla a revisión.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
alert('Las plantillas no se pueden editar. Crea una nueva plantilla si necesitas modificar el contenido.');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.deleteTemplate = function (templateId) {
|
window.deleteTemplate = function (templateId) {
|
||||||
console.log('Eliminando plantilla:', templateId);
|
console.log('Eliminando plantilla:', templateId);
|
||||||
if (confirm(`¿Está seguro que desea eliminar la plantilla ${templateId}?`)) {
|
|
||||||
alert(`Eliminar plantilla ${templateId} - Función en desarrollo`);
|
// Buscar la plantilla para mostrar información
|
||||||
|
let templateName = 'Plantilla ' + templateId;
|
||||||
|
|
||||||
|
if (window.whatsappManager && window.whatsappManager.templatesData) {
|
||||||
|
const template = window.whatsappManager.templatesData.find(t => t.id == templateId);
|
||||||
|
if (template) {
|
||||||
|
templateName = template.name || 'Plantilla ' + templateId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (confirm(`¿Está seguro que desea eliminar la plantilla "${templateName}"?\n\nEsta acción no se puede deshacer.`)) {
|
||||||
|
if (window.whatsappManager) {
|
||||||
|
window.whatsappManager.deleteTemplateAction(templateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Función para editar usuario - Modal simple
|
||||||
|
window.showEditUserModal = function(user) {
|
||||||
|
const modalHtml = `
|
||||||
|
<div class="modal fade" id="editUserModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-primary text-white">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
<i class="fas fa-user-edit"></i> Editar Usuario
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="edit-user-form">
|
||||||
|
<input type="hidden" id="edit-user-id" value="${user.id}">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Teléfono</label>
|
||||||
|
<input type="text" class="form-control" value="${user.phone_number}" readonly>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nombre</label>
|
||||||
|
<input type="text" class="form-control" id="edit-user-name" value="${user.name || ''}" placeholder="Nombre del usuario">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Estado</label>
|
||||||
|
<select class="form-control" id="edit-user-status">
|
||||||
|
<option value="active" ${user.status === 'active' ? 'selected' : ''}>Activo</option>
|
||||||
|
<option value="inactive" ${user.status === 'inactive' ? 'selected' : ''}>Inactivo</option>
|
||||||
|
<option value="blocked" ${user.status === 'blocked' ? 'selected' : ''}>Bloqueado</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="saveEditedUser()">
|
||||||
|
<i class="fas fa-save"></i> Guardar Cambios
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Eliminar modal anterior si existe
|
||||||
|
const existingModal = document.getElementById('editUserModal');
|
||||||
|
if (existingModal) {
|
||||||
|
existingModal.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar nuevo modal
|
||||||
|
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
||||||
|
|
||||||
|
// Mostrar modal
|
||||||
|
const modal = new bootstrap.Modal(document.getElementById('editUserModal'));
|
||||||
|
modal.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Función para guardar usuario editado
|
||||||
|
window.saveEditedUser = async function() {
|
||||||
|
const userId = document.getElementById('edit-user-id').value;
|
||||||
|
const name = document.getElementById('edit-user-name').value;
|
||||||
|
const status = document.getElementById('edit-user-status').value;
|
||||||
|
|
||||||
|
if (window.whatsappManager) {
|
||||||
|
try {
|
||||||
|
const response = await window.whatsappManager.apiCall('update_user.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
id: userId,
|
||||||
|
name: name,
|
||||||
|
status: status
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response && response.success) {
|
||||||
|
window.whatsappManager.showSuccess('Usuario actualizado correctamente');
|
||||||
|
|
||||||
|
// Cerrar modal
|
||||||
|
const modal = bootstrap.Modal.getInstance(document.getElementById('editUserModal'));
|
||||||
|
if (modal) modal.hide();
|
||||||
|
|
||||||
|
// Recargar lista
|
||||||
|
window.whatsappManager.loadUsers();
|
||||||
|
} else {
|
||||||
|
window.whatsappManager.showError(`Error: ${response?.error || 'Error desconocido'}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
window.whatsappManager.showError('Error actualizando usuario: ' + error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2228,11 +2434,7 @@ window.removeMenuOption = function (button) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Funciones globales para gestión de respuestas automáticas
|
// Funciones globales para gestión de respuestas automáticas
|
||||||
window.editAutoResponse = function (responseId) {
|
// La función real está más abajo en el archivo (línea ~2390)
|
||||||
console.log('Editando respuesta automática:', responseId);
|
|
||||||
// TODO: Implementar edición de respuestas automáticas
|
|
||||||
alert(`Editar respuesta automática ${responseId} - Función en desarrollo`);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.deleteAutoResponse = function (responseId) {
|
window.deleteAutoResponse = function (responseId) {
|
||||||
console.log('Eliminando respuesta automática:', responseId);
|
console.log('Eliminando respuesta automática:', responseId);
|
||||||
|
|||||||
@@ -0,0 +1,366 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Test de Webhook - Diagnóstico completo
|
||||||
|
* Fecha: 13 de enero de 2026
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'config/config.php';
|
||||||
|
|
||||||
|
// Verificar autenticación
|
||||||
|
if (!isUserLoggedIn()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Diagnóstico de Webhook - WhatsApp Bot</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<style>
|
||||||
|
body { background: #f8f9fa; padding: 20px; }
|
||||||
|
.test-card { background: white; border-radius: 10px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||||
|
.ok { color: #28a745; font-weight: bold; }
|
||||||
|
.error { color: #dc3545; font-weight: bold; }
|
||||||
|
.warning { color: #ffc107; font-weight: bold; }
|
||||||
|
.info { color: #17a2b8; font-weight: bold; }
|
||||||
|
.code-box { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 5px; padding: 15px; margin: 10px 0; font-family: 'Courier New', monospace; font-size: 12px; }
|
||||||
|
.badge-status { font-size: 14px; padding: 8px 15px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="test-card">
|
||||||
|
<h1 class="mb-4">
|
||||||
|
<i class="fas fa-plug"></i> Diagnóstico de Webhook WhatsApp
|
||||||
|
</h1>
|
||||||
|
<p class="text-muted">Verificación completa del estado del webhook y configuración</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$allOk = true;
|
||||||
|
|
||||||
|
// Test 1: Verificar configuración
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-cog'></i> 1. Configuración del Sistema</h3>";
|
||||||
|
|
||||||
|
$config = [
|
||||||
|
'WHATSAPP_TOKEN' => defined('WHATSAPP_TOKEN') ? WHATSAPP_TOKEN : null,
|
||||||
|
'WHATSAPP_PHONE_NUMBER_ID' => defined('WHATSAPP_PHONE_NUMBER_ID') ? WHATSAPP_PHONE_NUMBER_ID : null,
|
||||||
|
'WEBHOOK_VERIFY_TOKEN' => defined('WEBHOOK_VERIFY_TOKEN') ? WEBHOOK_VERIFY_TOKEN : null,
|
||||||
|
'WHATSAPP_API_URL' => defined('WHATSAPP_API_URL') ? WHATSAPP_API_URL : null,
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<table class='table table-sm'>";
|
||||||
|
foreach ($config as $key => $value) {
|
||||||
|
$status = !empty($value) ? 'ok' : 'error';
|
||||||
|
$icon = !empty($value) ? '✅' : '❌';
|
||||||
|
$displayValue = !empty($value) ? (strlen($value) > 30 ? substr($value, 0, 30) . '...' : $value) : 'NO CONFIGURADO';
|
||||||
|
|
||||||
|
if ($status === 'error') $allOk = false;
|
||||||
|
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td class='$status'>$icon $key</td>";
|
||||||
|
echo "<td><code>$displayValue</code></td>";
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
echo "</table>";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Test 2: URL del Webhook
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-link'></i> 2. URL del Webhook</h3>";
|
||||||
|
|
||||||
|
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
||||||
|
$host = $_SERVER['HTTP_HOST'];
|
||||||
|
$webhookUrl = $protocol . '://' . $host . '/api/webhook.php';
|
||||||
|
|
||||||
|
echo "<div class='alert alert-info'>";
|
||||||
|
echo "<strong>URL para configurar en Meta/Facebook:</strong><br>";
|
||||||
|
echo "<code style='font-size: 14px;'>$webhookUrl</code>";
|
||||||
|
echo "<button class='btn btn-sm btn-outline-primary ms-2' onclick='navigator.clipboard.writeText(\"$webhookUrl\")'>
|
||||||
|
<i class='fas fa-copy'></i> Copiar
|
||||||
|
</button>";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Verificar si el archivo existe
|
||||||
|
$webhookFile = __DIR__ . '/api/webhook.php';
|
||||||
|
if (file_exists($webhookFile)) {
|
||||||
|
echo "<p class='ok'>✅ Archivo webhook.php existe</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p class='error'>❌ Archivo webhook.php NO encontrado</p>";
|
||||||
|
$allOk = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Test 3: Verificación GET
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-check-circle'></i> 3. Test de Verificación (GET)</h3>";
|
||||||
|
|
||||||
|
$verifyUrl = $webhookUrl . '?hub.mode=subscribe&hub.verify_token=' . urlencode(WEBHOOK_VERIFY_TOKEN) . '&hub.challenge=test_challenge_12345';
|
||||||
|
|
||||||
|
echo "<p><strong>URL de prueba:</strong></p>";
|
||||||
|
echo "<div class='code-box'>" . htmlspecialchars($verifyUrl) . "</div>";
|
||||||
|
|
||||||
|
echo "<div class='alert alert-info'>";
|
||||||
|
echo "<strong>💡 Nota:</strong> Este test intenta verificar el webhook desde el servidor mismo. ";
|
||||||
|
echo "Si estás en localhost, es normal que falle. Lo importante es que el archivo exista y esté configurado correctamente.";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Intentar hacer la verificación solo si no es localhost
|
||||||
|
$isLocalhost = (strpos($host, 'localhost') !== false || strpos($host, '127.0.0.1') !== false);
|
||||||
|
|
||||||
|
if (!$isLocalhost) {
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $verifyUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode == 200 && $response === 'test_challenge_12345') {
|
||||||
|
echo "<p class='ok'>✅ Verificación GET exitosa - El webhook responde correctamente</p>";
|
||||||
|
echo "<p>Respuesta: <code>$response</code></p>";
|
||||||
|
} else {
|
||||||
|
echo "<p class='error'>❌ Error en verificación GET</p>";
|
||||||
|
echo "<p>Código HTTP: <code>$httpCode</code></p>";
|
||||||
|
echo "<p>Respuesta: <code>" . htmlspecialchars($response) . "</code></p>";
|
||||||
|
if ($error) echo "<p>Error cURL: <code>$error</code></p>";
|
||||||
|
$allOk = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Test manual para localhost
|
||||||
|
echo "<div class='alert alert-warning'>";
|
||||||
|
echo "<strong>⚠️ Entorno Local Detectado</strong><br>";
|
||||||
|
echo "No se puede hacer la verificación automática en localhost. ";
|
||||||
|
echo "En su lugar, puedes probar manualmente:";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
echo "<ol>";
|
||||||
|
echo "<li>Haz clic en el botón de abajo para probar el webhook</li>";
|
||||||
|
echo "<li>Deberías ver el texto: <code>test_challenge_12345</code></li>";
|
||||||
|
echo "</ol>";
|
||||||
|
|
||||||
|
echo "<a href='$verifyUrl' target='_blank' class='btn btn-primary mb-3'>";
|
||||||
|
echo "<i class='fas fa-external-link-alt'></i> Probar Webhook Manualmente";
|
||||||
|
echo "</a>";
|
||||||
|
|
||||||
|
// Verificar el archivo directamente
|
||||||
|
$webhookFilePath = __DIR__ . '/api/webhook.php';
|
||||||
|
if (file_exists($webhookFilePath)) {
|
||||||
|
echo "<p class='ok'>✅ El archivo webhook.php existe y es accesible</p>";
|
||||||
|
|
||||||
|
// Verificar permisos de lectura
|
||||||
|
if (is_readable($webhookFilePath)) {
|
||||||
|
echo "<p class='ok'>✅ El archivo tiene permisos de lectura</p>";
|
||||||
|
|
||||||
|
// Verificar que contenga el código necesario
|
||||||
|
$webhookContent = file_get_contents($webhookFilePath);
|
||||||
|
if (strpos($webhookContent, 'hub_verify_token') !== false &&
|
||||||
|
strpos($webhookContent, 'hub_challenge') !== false) {
|
||||||
|
echo "<p class='ok'>✅ El archivo contiene el código de verificación correcto</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p class='warning'>⚠️ El archivo puede no contener el código de verificación</p>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "<p class='error'>❌ El archivo no tiene permisos de lectura</p>";
|
||||||
|
$allOk = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Test 4: Estructura de tablas
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-database'></i> 4. Estructura de Base de Datos</h3>";
|
||||||
|
|
||||||
|
$requiredTables = ['users', 'conversations', 'menus', 'menu_options', 'autoresponses', 'webhook_logs'];
|
||||||
|
|
||||||
|
echo "<table class='table table-sm'>";
|
||||||
|
foreach ($requiredTables as $table) {
|
||||||
|
$exists = $db->fetchAll("SHOW TABLES LIKE '$table'");
|
||||||
|
$status = !empty($exists) ? 'ok' : 'error';
|
||||||
|
$icon = !empty($exists) ? '✅' : '❌';
|
||||||
|
|
||||||
|
if ($status === 'error') $allOk = false;
|
||||||
|
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td class='$status'>$icon Tabla: <strong>$table</strong></td>";
|
||||||
|
|
||||||
|
if (!empty($exists)) {
|
||||||
|
// Contar registros
|
||||||
|
$count = $db->fetch("SELECT COUNT(*) as total FROM $table");
|
||||||
|
echo "<td><span class='badge bg-info'>{$count['total']} registros</span></td>";
|
||||||
|
} else {
|
||||||
|
echo "<td><span class='badge bg-danger'>NO EXISTE</span></td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
echo "</table>";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Test 5: Últimos mensajes recibidos
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-inbox'></i> 5. Mensajes Recibidos Recientemente</h3>";
|
||||||
|
|
||||||
|
$recentMessages = $db->fetchAll(
|
||||||
|
"SELECT c.*, u.phone_number, u.name
|
||||||
|
FROM conversations c
|
||||||
|
LEFT JOIN users u ON c.user_id = u.id
|
||||||
|
WHERE c.direction = 'incoming'
|
||||||
|
ORDER BY c.created_at DESC
|
||||||
|
LIMIT 5"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($recentMessages)) {
|
||||||
|
echo "<p class='ok'>✅ Se encontraron mensajes entrantes</p>";
|
||||||
|
echo "<table class='table table-sm table-striped'>";
|
||||||
|
echo "<thead><tr><th>Fecha</th><th>Usuario</th><th>Mensaje</th><th>Estado</th></tr></thead>";
|
||||||
|
echo "<tbody>";
|
||||||
|
foreach ($recentMessages as $msg) {
|
||||||
|
$date = date('d/m/Y H:i', strtotime($msg['created_at']));
|
||||||
|
$phone = $msg['phone_number'] ?? 'Desconocido';
|
||||||
|
$content = htmlspecialchars(substr($msg['content'], 0, 50));
|
||||||
|
$status = $msg['status'];
|
||||||
|
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td>$date</td>";
|
||||||
|
echo "<td>$phone</td>";
|
||||||
|
echo "<td>$content</td>";
|
||||||
|
echo "<td><span class='badge bg-success'>$status</span></td>";
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
echo "</tbody></table>";
|
||||||
|
} else {
|
||||||
|
echo "<p class='warning'>⚠️ No se encontraron mensajes entrantes. El webhook puede no estar recibiendo datos.</p>";
|
||||||
|
echo "<div class='alert alert-warning'>";
|
||||||
|
echo "<strong>Posibles causas:</strong><ul>";
|
||||||
|
echo "<li>El webhook no está configurado en Meta/Facebook</li>";
|
||||||
|
echo "<li>La URL del webhook es incorrecta</li>";
|
||||||
|
echo "<li>El servidor no es accesible desde Internet</li>";
|
||||||
|
echo "<li>Aún no se han enviado mensajes de prueba</li>";
|
||||||
|
echo "</ul></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Test 6: Webhook Logs
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-file-alt'></i> 6. Logs del Webhook</h3>";
|
||||||
|
|
||||||
|
$webhookLogs = $db->fetchAll(
|
||||||
|
"SELECT * FROM webhook_logs
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT 5"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($webhookLogs)) {
|
||||||
|
echo "<p class='ok'>✅ Se encontraron logs del webhook</p>";
|
||||||
|
echo "<table class='table table-sm'>";
|
||||||
|
echo "<thead><tr><th>Fecha</th><th>Status</th><th>IP</th><th>Detalles</th></tr></thead>";
|
||||||
|
echo "<tbody>";
|
||||||
|
foreach ($webhookLogs as $log) {
|
||||||
|
$date = date('d/m/Y H:i:s', strtotime($log['created_at']));
|
||||||
|
$status = $log['status_code'];
|
||||||
|
$ip = $log['ip_address'];
|
||||||
|
$statusClass = $status == 200 ? 'success' : 'danger';
|
||||||
|
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td>$date</td>";
|
||||||
|
echo "<td><span class='badge bg-$statusClass'>$status</span></td>";
|
||||||
|
echo "<td>$ip</td>";
|
||||||
|
echo "<td><button class='btn btn-sm btn-outline-info' onclick='alert(\"Request: " . addslashes(substr($log['request_body'], 0, 200)) . "\")'>Ver</button></td>";
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
echo "</tbody></table>";
|
||||||
|
} else {
|
||||||
|
echo "<p class='info'>ℹ️ No hay logs del webhook registrados</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Test 7: Configuración de Menús y Respuestas
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
echo "<h3><i class='fas fa-robot'></i> 7. Configuración del Bot</h3>";
|
||||||
|
|
||||||
|
$menuCount = $db->fetch("SELECT COUNT(*) as total FROM menus WHERE is_active = 1");
|
||||||
|
$optionCount = $db->fetch("SELECT COUNT(*) as total FROM menu_options WHERE is_active = 1");
|
||||||
|
$autoResponseCount = $db->fetch("SELECT COUNT(*) as total FROM autoresponses WHERE is_active = 1");
|
||||||
|
|
||||||
|
echo "<div class='row'>";
|
||||||
|
echo "<div class='col-md-4'>";
|
||||||
|
echo "<div class='alert alert-info text-center'>";
|
||||||
|
echo "<h4>{$menuCount['total']}</h4>";
|
||||||
|
echo "<p>Menús Activos</p>";
|
||||||
|
echo "</div>";
|
||||||
|
echo "</div>";
|
||||||
|
echo "<div class='col-md-4'>";
|
||||||
|
echo "<div class='alert alert-info text-center'>";
|
||||||
|
echo "<h4>{$optionCount['total']}</h4>";
|
||||||
|
echo "<p>Opciones de Menú</p>";
|
||||||
|
echo "</div>";
|
||||||
|
echo "</div>";
|
||||||
|
echo "<div class='col-md-4'>";
|
||||||
|
echo "<div class='alert alert-info text-center'>";
|
||||||
|
echo "<h4>{$autoResponseCount['total']}</h4>";
|
||||||
|
echo "<p>Respuestas Automáticas</p>";
|
||||||
|
echo "</div>";
|
||||||
|
echo "</div>";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
// Resumen final
|
||||||
|
echo "<div class='test-card'>";
|
||||||
|
if ($allOk) {
|
||||||
|
echo "<div class='alert alert-success'>";
|
||||||
|
echo "<h4><i class='fas fa-check-circle'></i> ¡Sistema Configurado Correctamente!</h4>";
|
||||||
|
echo "<p>El webhook está listo para recibir mensajes de WhatsApp.</p>";
|
||||||
|
echo "</div>";
|
||||||
|
} else {
|
||||||
|
echo "<div class='alert alert-danger'>";
|
||||||
|
echo "<h4><i class='fas fa-exclamation-triangle'></i> Se encontraron problemas</h4>";
|
||||||
|
echo "<p>Revisa los errores anteriores y corrígelos antes de continuar.</p>";
|
||||||
|
echo "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<div class='mt-3'>";
|
||||||
|
echo "<h5>Próximos pasos:</h5>";
|
||||||
|
echo "<ol>";
|
||||||
|
echo "<li>Copia la URL del webhook y configúrala en Meta Developer Console</li>";
|
||||||
|
echo "<li>Usa el token de verificación: <code>" . WEBHOOK_VERIFY_TOKEN . "</code></li>";
|
||||||
|
echo "<li>Envía un mensaje de prueba desde WhatsApp</li>";
|
||||||
|
echo "<li>Verifica que aparezca en la sección de mensajes recibidos</li>";
|
||||||
|
echo "</ol>";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
echo "</div>";
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="text-center mt-4">
|
||||||
|
<a href="index.php" class="btn btn-primary">
|
||||||
|
<i class="fas fa-home"></i> Volver al Dashboard
|
||||||
|
</a>
|
||||||
|
<button onclick="location.reload()" class="btn btn-secondary">
|
||||||
|
<i class="fas fa-sync"></i> Recargar Test
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user