This commit is contained in:
Lizandro Guarnizo
2026-01-22 14:10:03 -05:00
parent 74955aef32
commit 2aed2c428c
3 changed files with 62 additions and 16 deletions
+4 -2
View File
@@ -159,11 +159,13 @@ try {
error_log("===================================="); error_log("====================================");
// Si viene reply_to, usar reply con contexto // Si viene reply_to, usar reply con contexto
$operatorId = $_SESSION['admin_user']['id'] ?? null;
if (!empty($input['reply_to'])) { if (!empty($input['reply_to'])) {
$replyTo = $input['reply_to']; $replyTo = $input['reply_to'];
$response = $whatsappService->sendTextReply($recipient, $replyTo, $input['message']); $response = $whatsappService->sendTextReply($recipient, $replyTo, $input['message'], $operatorId ? ['operator_id' => $operatorId] : null);
} else { } else {
$response = $whatsappService->sendTextMessage($recipient, $input['message']); $response = $whatsappService->sendTextMessage($recipient, $input['message'], $operatorId ? ['operator_id' => $operatorId] : null);
} }
break; break;
+24 -5
View File
@@ -63,13 +63,31 @@ class BotService {
try { try {
// Support masculino/femenino, singular/plural: enviado, enviada, enviados, enviadas // Support masculino/femenino, singular/plural: enviado, enviada, enviados, enviadas
if (preg_match('/\b(enviad[oa]s?)\b/iu', $messageText)) { if (preg_match('/\b(enviad[oa]s?)\b/iu', $messageText)) {
$ack = "📄 Informacion recibida, Estaremos procesando su solicitud y confirmaremos en unos minutos"; // NO enviar respuesta al usuario (para conservar el indicador de atención en la lista).
// En su lugar, marcar la conversación como que requiere atención y crear un mensaje 'system'
try { try {
$this->whatsappService->sendTextMessage($phoneNumber, $ack); $this->db->update('users', ['advisor_requested' => 1], 'phone_number = :phone', ['phone' => $phoneNumber]);
$sys = [
'system' => 'attention',
'type' => 'user_sent_documents',
'text' => 'El usuario indicó que ha enviado documentos o información; requiere atención.'
];
$this->db->insert('conversations', [
'user_id' => $user['id'],
'direction' => 'incoming',
'message_type' => 'text',
'content' => json_encode($sys),
'status' => 'received',
'created_at' => date('Y-m-d H:i:s')
]);
} catch (Exception $e) { } catch (Exception $e) {
// ignore send errors error_log('[BotService] failed to mark advisor_requested on envio: ' . $e->getMessage());
} }
error_log("[BotService] processMessage - sent 'enviados' ack to user {$user['id']}");
error_log("[BotService] processMessage - marked advisor_requested for user {$user['id']} (no outgoing message sent)");
return; return;
} }
} catch (Throwable $t) { } catch (Throwable $t) {
@@ -491,7 +509,8 @@ class BotService {
try { try {
$pausedUntil = date('Y-m-d H:i:s', strtotime("+{$minutes} minutes")); $pausedUntil = date('Y-m-d H:i:s', strtotime("+{$minutes} minutes"));
// Guardar bandera y tiempo de expiración (usamos bot_paused_until que ya existe) // Guardar bandera y tiempo de expiración (usamos bot_paused_until que ya existe)
$this->db->update('users', ['on_hold' => 1, 'bot_paused_until' => $pausedUntil, 'advisor_requested' => 0], 'phone_number = :phone', ['phone' => $phoneNumber]); $this->db->update('users', ['on_hold' => 1, 'bot_paused_until' => $pausedUntil, 'advisor_requested' => 1], 'phone_number = :phone', ['phone' => $phoneNumber]);
// Enviar mensaje (bot) marcando la solicitud; no incluimos metadata de operador para evitar limpiar la marca
$this->whatsappService->sendTextMessage($phoneNumber, "🔔 Se ha solicitado un asesor. Te hemos puesto en espera por {$minutes} minutos. Si no hay respuesta, podrás volver a usar *menu*." ); $this->whatsappService->sendTextMessage($phoneNumber, "🔔 Se ha solicitado un asesor. Te hemos puesto en espera por {$minutes} minutos. Si no hay respuesta, podrás volver a usar *menu*." );
if (function_exists('writeLog')) writeLog('INFO', "Advisor requested for $phoneNumber until $pausedUntil"); if (function_exists('writeLog')) writeLog('INFO', "Advisor requested for $phoneNumber until $pausedUntil");
} catch (Exception $e) { } catch (Exception $e) {
+34 -9
View File
@@ -35,7 +35,7 @@ class WhatsAppService
/** /**
* Enviar mensaje de texto * Enviar mensaje de texto
*/ */
public function sendTextMessage($to, $message) public function sendTextMessage($to, $message, $meta = null)
{ {
$data = [ $data = [
'messaging_product' => 'whatsapp', 'messaging_product' => 'whatsapp',
@@ -46,6 +46,11 @@ class WhatsAppService
] ]
]; ];
if (!empty($meta) && is_array($meta)) {
// internal metadata used by our application (not sent to WhatsApp API)
$data['__app_meta'] = $meta;
}
return $this->sendMessage($data); return $this->sendMessage($data);
} }
@@ -58,7 +63,8 @@ class WhatsAppService
$language = 'es', $language = 'es',
$bodyParameters = [], $bodyParameters = [],
$headerParameters = [], $headerParameters = [],
$rawComponents = null $rawComponents = null,
$meta = null
) { ) {
// Si se pasan components completos (por ejemplo flow/button/image), úsalos tal cual // Si se pasan components completos (por ejemplo flow/button/image), úsalos tal cual
if (is_array($rawComponents) && !empty($rawComponents)) { if (is_array($rawComponents) && !empty($rawComponents)) {
@@ -140,6 +146,11 @@ class WhatsAppService
'template' => $template 'template' => $template
]; ];
if (!empty($meta) && is_array($meta)) {
// internal metadata used by our application (not sent to WhatsApp API)
$data['__app_meta'] = $meta;
}
return $this->sendMessage($data); return $this->sendMessage($data);
} }
@@ -402,12 +413,18 @@ class WhatsAppService
// Construir URL correcto para enviar mensajes (use /messages) // Construir URL correcto para enviar mensajes (use /messages)
$url = rtrim($this->apiUrl, '/') . '/' . $this->phoneNumberId . '/messages'; $url = rtrim($this->apiUrl, '/') . '/' . $this->phoneNumberId . '/messages';
// Debug log // Prepare payload (remove internal app meta before sending to WhatsApp API)
$payload = $data;
if (isset($payload['__app_meta'])) {
unset($payload['__app_meta']);
}
// Debug log (payload sent to WhatsApp)
error_log("WhatsApp API URL: " . $url); error_log("WhatsApp API URL: " . $url);
error_log("WhatsApp Token length: " . strlen($this->token)); error_log("WhatsApp Token length: " . strlen($this->token));
error_log("WhatsApp Data: " . json_encode($data)); error_log("WhatsApp Payload: " . json_encode($payload));
$response = $this->makeRequest('POST', $url, $data); $response = $this->makeRequest('POST', $url, $payload);
// Guardar mensaje enviado en la base de datos (respuesta puede contener 'messages' o 'conversations') // Guardar mensaje enviado en la base de datos (respuesta puede contener 'messages' o 'conversations')
$sentMessageId = null; $sentMessageId = null;
@@ -545,10 +562,14 @@ class WhatsAppService
$this->db->insert('conversations', $messageData); $this->db->insert('conversations', $messageData);
// Si un asesor envía un mensaje, limpiar la solicitud de asesor (advisor_requested) // Solo limpiar advisor_requested si el mensaje fue enviado por un asesor (operator)
try { try {
$this->db->update('users', ['advisor_requested' => 0, 'on_hold' => 0, 'bot_paused_until' => null], 'id = :id', ['id' => $user['id']]); $cleared = false;
if (function_exists('writeLog')) writeLog('INFO', "Cleared advisor_requested for user {$user['id']} after outgoing message"); if (isset($data['__app_meta']) && is_array($data['__app_meta']) && !empty($data['__app_meta']['operator_id'])) {
$this->db->update('users', ['advisor_requested' => 0, 'on_hold' => 0, 'bot_paused_until' => null], 'id = :id', ['id' => $user['id']]);
$cleared = true;
}
if ($cleared && function_exists('writeLog')) writeLog('INFO', "Cleared advisor_requested for user {$user['id']} after outgoing message by operator");
} catch (Exception $e) { } catch (Exception $e) {
error_log('Failed to clear advisor_requested after outgoing: ' . $e->getMessage()); error_log('Failed to clear advisor_requested after outgoing: ' . $e->getMessage());
} }
@@ -610,7 +631,7 @@ class WhatsAppService
* @param bool $preview_url Incluir preview_url en body.text * @param bool $preview_url Incluir preview_url en body.text
* @param bool $dryRun Si true, no hace la petición y devuelve el payload * @param bool $dryRun Si true, no hace la petición y devuelve el payload
*/ */
public function sendTextReply($to, $messageId, $text, $preview_url = false, $dryRun = false) public function sendTextReply($to, $messageId, $text, $preview_url = false, $dryRun = false, $meta = null)
{ {
$data = [ $data = [
'messaging_product' => 'whatsapp', 'messaging_product' => 'whatsapp',
@@ -625,6 +646,10 @@ class WhatsAppService
] ]
]; ];
if (!empty($meta) && is_array($meta)) {
$data['__app_meta'] = $meta;
}
if ($dryRun) return $data; if ($dryRun) return $data;
return $this->sendMessage($data); return $this->sendMessage($data);
} }