diff --git a/api/send_message.php b/api/send_message.php index ccf3ac1..21e1929 100644 --- a/api/send_message.php +++ b/api/send_message.php @@ -159,11 +159,13 @@ try { error_log("===================================="); // Si viene reply_to, usar reply con contexto + $operatorId = $_SESSION['admin_user']['id'] ?? null; + if (!empty($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 { - $response = $whatsappService->sendTextMessage($recipient, $input['message']); + $response = $whatsappService->sendTextMessage($recipient, $input['message'], $operatorId ? ['operator_id' => $operatorId] : null); } break; diff --git a/services/BotService.php b/services/BotService.php index a39c1e0..5e473d8 100644 --- a/services/BotService.php +++ b/services/BotService.php @@ -63,13 +63,31 @@ class BotService { try { // Support masculino/femenino, singular/plural: enviado, enviada, enviados, enviadas 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 { - $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) { - // 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; } } catch (Throwable $t) { @@ -491,7 +509,8 @@ class BotService { try { $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) - $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*." ); if (function_exists('writeLog')) writeLog('INFO', "Advisor requested for $phoneNumber until $pausedUntil"); } catch (Exception $e) { diff --git a/services/WhatsAppService.php b/services/WhatsAppService.php index eab1576..46c50f4 100644 --- a/services/WhatsAppService.php +++ b/services/WhatsAppService.php @@ -35,7 +35,7 @@ class WhatsAppService /** * Enviar mensaje de texto */ - public function sendTextMessage($to, $message) + public function sendTextMessage($to, $message, $meta = null) { $data = [ '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); } @@ -58,7 +63,8 @@ class WhatsAppService $language = 'es', $bodyParameters = [], $headerParameters = [], - $rawComponents = null + $rawComponents = null, + $meta = null ) { // Si se pasan components completos (por ejemplo flow/button/image), 煤salos tal cual if (is_array($rawComponents) && !empty($rawComponents)) { @@ -140,6 +146,11 @@ class WhatsAppService '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); } @@ -402,12 +413,18 @@ class WhatsAppService // Construir URL correcto para enviar mensajes (use /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 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') $sentMessageId = null; @@ -545,10 +562,14 @@ class WhatsAppService $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 { - $this->db->update('users', ['advisor_requested' => 0, 'on_hold' => 0, 'bot_paused_until' => null], 'id = :id', ['id' => $user['id']]); - if (function_exists('writeLog')) writeLog('INFO', "Cleared advisor_requested for user {$user['id']} after outgoing message"); + $cleared = false; + 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) { 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 $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 = [ 'messaging_product' => 'whatsapp', @@ -625,6 +646,10 @@ class WhatsAppService ] ]; + if (!empty($meta) && is_array($meta)) { + $data['__app_meta'] = $meta; + } + if ($dryRun) return $data; return $this->sendMessage($data); }