up
This commit is contained in:
+13
-2
@@ -227,12 +227,23 @@ class WhatsAppWebhook {
|
||||
);
|
||||
}
|
||||
|
||||
private function createUser($phoneNumber) {
|
||||
return $this->db->insert('users', [
|
||||
private function createUser($phoneNumber, $sendWelcome = true) {
|
||||
$id = $this->db->insert('users', [
|
||||
'phone_number' => $phoneNumber,
|
||||
'status' => 'active',
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
if ($sendWelcome && $id) {
|
||||
try {
|
||||
// Enviar mensaje de bienvenida usando el BotService (que consulta system_config)
|
||||
$this->botService->sendWelcomeMessage($phoneNumber);
|
||||
} catch (Throwable $t) {
|
||||
error_log('Failed to send welcome message: ' . $t->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
private function saveMessage($messageData) {
|
||||
|
||||
@@ -18,3 +18,8 @@ Stack trace:
|
||||
[20-Jan-2026 23:54:02 America/Bogota] [webhook] __construct start
|
||||
[20-Jan-2026 23:54:03 America/Bogota] [webhook] __construct end
|
||||
[20-Jan-2026 23:54:03 America/Bogota] [webhook] handleRequest start, method=GET
|
||||
[2026-01-21 02:30:13] [INFO] Advisor requested for 573010000123
|
||||
[2026-01-21 02:31:08] [INFO] Advisor requested for 573010000123
|
||||
[2026-01-21 02:31:42] [INFO] Advisor requested for 573010000123
|
||||
[2026-01-21 02:31:44] [INFO] Advisor released hold for 573010000123
|
||||
[2026-01-21 02:31:49] [INFO] Bot paused for 4 hours for 573010000123
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
$db = Database::getInstance();
|
||||
$col = $db->fetch("SHOW COLUMNS FROM users LIKE 'bot_paused_until'");
|
||||
if ($col) {
|
||||
echo "Column bot_paused_until already exists\n";
|
||||
exit(0);
|
||||
}
|
||||
try {
|
||||
$db->query("ALTER TABLE users ADD COLUMN bot_paused_until DATETIME NULL AFTER on_hold");
|
||||
echo "Added column bot_paused_until\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Failed to add bot_paused_until: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
$db = Database::getInstance();
|
||||
$col = $db->fetch("SHOW COLUMNS FROM users LIKE 'on_hold'");
|
||||
if ($col) {
|
||||
echo "Column on_hold already exists\n";
|
||||
exit(0);
|
||||
}
|
||||
try {
|
||||
$db->query("ALTER TABLE users ADD COLUMN on_hold TINYINT(1) NULL DEFAULT 0 AFTER status");
|
||||
echo "Added column on_hold\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Failed to add on_hold: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
$db = Database::getInstance();
|
||||
$col = $db->fetch("SHOW COLUMNS FROM users LIKE 'welcome_sent_at'");
|
||||
if ($col) {
|
||||
echo "Column welcome_sent_at already exists\n";
|
||||
exit(0);
|
||||
}
|
||||
try {
|
||||
$db->query("ALTER TABLE users ADD COLUMN welcome_sent_at DATETIME NULL AFTER created_at");
|
||||
echo "Added column welcome_sent_at\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Failed to add welcome_sent_at: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
require_once __DIR__ . '/../services/BotService.php';
|
||||
|
||||
$db = Database::getInstance();
|
||||
$bot = new BotService();
|
||||
|
||||
// Crear usuario de prueba
|
||||
$phone = '573010000123';
|
||||
$db->execute('DELETE FROM users WHERE phone_number = :p', ['p' => $phone]);
|
||||
$userId = $db->insert('users', ['phone_number' => $phone, 'status' => 'active', 'created_at' => date('Y-m-d H:i:s')]);
|
||||
$user = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $userId]);
|
||||
|
||||
// Simular comando asesor
|
||||
$bot->processMessage($user, 'asesor', 'text');
|
||||
// Intentar también llamar directamente putOnHold para comprobar
|
||||
$bot->putOnHold($phone);
|
||||
$user2 = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $userId]);
|
||||
echo "User after putOnHold: " . json_encode($user2) . "\n";
|
||||
if ($user2['on_hold']) {
|
||||
echo "ON_HOLD set correctly for $phone\n";
|
||||
} else {
|
||||
echo "ON_HOLD NOT SET!\n";
|
||||
}
|
||||
|
||||
// Simular finalizar conversación via menu action (invoke processMenuAction indirectly)
|
||||
// Crear menu option end test: insert temporary menu and option
|
||||
$menuId = $db->insert('menus', ['name'=>'test_menu_end','title'=>'Test End','is_root'=>0,'is_active'=>1,'created_at'=>date('Y-m-d H:i:s')]);
|
||||
$optId = $db->insert('menu_options', ['menu_id'=>$menuId,'option_number'=>9,'text'=>'Terminar','action_type'=>'end','action_value'=>'Gracias, cerrando.','is_active'=>1,'created_at'=>date('Y-m-d H:i:s')]);
|
||||
// Liberar hold y luego establecer menu para probar pause
|
||||
$bot->releaseHold($phone);
|
||||
$db->update('users', ['current_menu_id'=>$menuId], 'id = :id', ['id' => $userId]);
|
||||
|
||||
// Simular selection '9' - recargar usuario para que tenga el current_menu_id
|
||||
$user = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $userId]);
|
||||
$bot->processMessage($user, '9', 'text');
|
||||
$user3 = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $userId]);
|
||||
if (!empty($user3['bot_paused_until'])) {
|
||||
echo "Bot paused until: {$user3['bot_paused_until']}\n";
|
||||
} else {
|
||||
echo "Bot pause NOT SET!\n";
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
$db->execute('DELETE FROM menu_options WHERE menu_id = :mid', ['mid' => $menuId]);
|
||||
$db->execute('DELETE FROM menus WHERE id = :id', ['id' => $menuId]);
|
||||
$db->execute('DELETE FROM users WHERE id = :id', ['id' => $userId]);
|
||||
|
||||
echo "Done\n";
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
require_once __DIR__ . '/../services/BotService.php';
|
||||
$db = Database::getInstance();
|
||||
$bot = new BotService();
|
||||
|
||||
$phone = '573011111222';
|
||||
$db->execute('DELETE FROM users WHERE phone_number = :p', ['p' => $phone]);
|
||||
$id = $db->insert('users', ['phone_number' => $phone, 'status' => 'active', 'created_at' => date('Y-m-d H:i:s')]);
|
||||
|
||||
// Ensure welcome_message config exists
|
||||
$message = getConfigFromDB('welcome_message', null);
|
||||
if (!$message) {
|
||||
$m = 'Bienvenido a nuestro servicio (mensaje por defecto)';
|
||||
// Insert config if missing
|
||||
try {
|
||||
$db->insert('system_config', ['config_key' => 'welcome_message', 'config_value' => $m, 'created_at' => date('Y-m-d H:i:s')]);
|
||||
echo "Inserted welcome_message config\n";
|
||||
} catch (Exception $e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
$bot->sendWelcomeMessage($phone);
|
||||
$user = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $id]);
|
||||
if (!empty($user['welcome_sent_at'])) {
|
||||
echo "welcome_sent_at recorded: {$user['welcome_sent_at']}\n";
|
||||
} else {
|
||||
echo "welcome_sent_at NOT set\n";
|
||||
}
|
||||
|
||||
// cleanup
|
||||
$db->execute('DELETE FROM users WHERE id = :id', ['id' => $id]);
|
||||
|
||||
echo "Done\n";
|
||||
+73
-6
@@ -35,13 +35,29 @@ class BotService {
|
||||
if ($this->processSpecialCommands($phoneNumber, $messageText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si el usuario está en espera por un asesor, no procesar
|
||||
if (!empty($user['on_hold']) && $user['on_hold']) {
|
||||
try {
|
||||
$this->whatsappService->sendTextMessage($phoneNumber, "⚠️ Has sido puesto en espera por un asesor. En breve te contactarán.");
|
||||
} catch (Exception $e) {
|
||||
// ignore
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Si el bot está pausado por bot_paused_until, no responder automáticamente
|
||||
if (!empty($user['bot_paused_until']) && strtotime($user['bot_paused_until']) > time()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si el asesor ya respondió después del último mensaje del usuario, frenar al bot
|
||||
$lastIncoming = $this->db->fetch("SELECT created_at FROM conversations WHERE user_id = :uid AND direction = 'incoming' ORDER BY created_at DESC LIMIT 1", ['uid' => $user['id']]);
|
||||
$lastOutgoing = $this->db->fetch("SELECT created_at FROM conversations WHERE user_id = :uid AND direction = 'outgoing' ORDER BY created_at DESC LIMIT 1", ['uid' => $user['id']]);
|
||||
if ($lastOutgoing && $lastIncoming && strtotime($lastOutgoing['created_at']) >= strtotime($lastIncoming['created_at'])) {
|
||||
// El asesor ya respondió, no enviar respuestas automáticas
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Verificar si el usuario está en un menú
|
||||
if ($user['current_menu_id']) {
|
||||
$this->processMenuSelection($user, $messageText);
|
||||
@@ -59,17 +75,29 @@ class BotService {
|
||||
"SELECT COUNT(*) as count FROM conversations WHERE user_id = :user_id",
|
||||
['user_id' => $userId]
|
||||
);
|
||||
|
||||
return $messageCount['count'] <= 1; // Solo el mensaje actual
|
||||
// Evitar reenviar welcome si ya se envió
|
||||
$user = $this->db->fetch("SELECT welcome_sent_at FROM users WHERE id = :id", ['id' => $userId]);
|
||||
$welcomeSent = !empty($user['welcome_sent_at']);
|
||||
return ($messageCount['count'] <= 1) && !$welcomeSent; // Solo el mensaje actual y si no se ha enviado welcome
|
||||
}
|
||||
|
||||
/**
|
||||
* Enviar mensaje de bienvenida
|
||||
*/
|
||||
private function sendWelcomeMessage($phoneNumber) {
|
||||
public function sendWelcomeMessage($phoneNumber) {
|
||||
$enabled = getConfigFromDB('welcome_enabled', '1');
|
||||
$welcomeMessage = getConfigFromDB('welcome_message', '¡Hola! 👋 Bienvenido a nuestro servicio automatizado. Escribe *menu* para ver las opciones disponibles.');
|
||||
|
||||
if (!$enabled || !$welcomeMessage) return;
|
||||
|
||||
$this->whatsappService->sendTextMessage($phoneNumber, $welcomeMessage);
|
||||
|
||||
// Registrar que se envió el welcome
|
||||
try {
|
||||
$this->db->update('users', ['welcome_sent_at' => date('Y-m-d H:i:s')], 'phone_number = :phone', ['phone' => $phoneNumber]);
|
||||
} catch (Exception $e) {
|
||||
error_log('Failed to set welcome_sent_at for ' . $phoneNumber . ': ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,7 +121,8 @@ class BotService {
|
||||
|
||||
case 'asesor':
|
||||
case 'ayuda':
|
||||
$this->showHelp($phoneNumber);
|
||||
// Poner la conversación en espera y notificar al usuario
|
||||
$this->putOnHold($phoneNumber);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -244,6 +273,8 @@ class BotService {
|
||||
$message = $option['action_value'] ?: "Gracias por usar nuestro servicio. ¡Hasta pronto!";
|
||||
$this->whatsappService->sendTextMessage($phoneNumber, $message);
|
||||
$this->exitMenu($phoneNumber);
|
||||
// Pausar el bot para esta conversación por 4 horas
|
||||
$this->pauseConversationForHours($phoneNumber, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -307,7 +338,43 @@ class BotService {
|
||||
['phone' => $phoneNumber]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Poner la conversación en pausa por 4 horas (llamada desde opciones 'end')
|
||||
*/
|
||||
private function pauseConversationForHours($phoneNumber, $hours = 4) {
|
||||
try {
|
||||
$pausedUntil = date('Y-m-d H:i:s', strtotime("+{$hours} hours"));
|
||||
$this->db->update('users', ['bot_paused_until' => $pausedUntil], 'phone_number = :phone', ['phone' => $phoneNumber]);
|
||||
if (function_exists('writeLog')) writeLog('INFO', "Bot paused for {$hours} hours for {$phoneNumber}");
|
||||
} catch (Exception $e) {
|
||||
error_log('pauseConversationForHours failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poner conversación en espera (asesor solicitado)
|
||||
*/
|
||||
public function putOnHold($phoneNumber) {
|
||||
try {
|
||||
$this->db->update('users', ['on_hold' => 1], 'phone_number = :phone', ['phone' => $phoneNumber]);
|
||||
$this->whatsappService->sendTextMessage($phoneNumber, "🔔 Se ha solicitado un asesor. Te hemos puesto en espera. Te contactaremos en breve.");
|
||||
if (function_exists('writeLog')) writeLog('INFO', "Advisor requested for $phoneNumber");
|
||||
} catch (Exception $e) {
|
||||
error_log('putOnHold failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function releaseHold($phoneNumber) {
|
||||
try {
|
||||
$this->db->update('users', ['on_hold' => 0], 'phone_number = :phone', ['phone' => $phoneNumber]);
|
||||
$this->whatsappService->sendTextMessage($phoneNumber, "🔔 Tu conversación ha sido retomada por el equipo.");
|
||||
if (function_exists('writeLog')) writeLog('INFO', "Advisor released hold for $phoneNumber");
|
||||
} catch (Exception $e) {
|
||||
error_log('releaseHold failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar estado del menú del usuario
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user