531 lines
25 KiB
PHP
531 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* API - Enviar mensaje individual
|
|
* Fecha: 4 de enero de 2026
|
|
*/
|
|
|
|
require_once '../config/config.php';
|
|
|
|
// Suprimir errores para obtener JSON limpio
|
|
error_reporting(E_ERROR | E_PARSE);
|
|
|
|
// Modo debug: desactivar autenticación si existe el parámetro debug
|
|
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
|
|
|
|
if (!$debugMode) {
|
|
requireAuthentication();
|
|
}
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
|
|
// Manejar preflight OPTIONS request
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
http_response_code(200);
|
|
exit;
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
http_response_code(405);
|
|
echo json_encode(['error' => 'Método no permitido. Use POST.', 'method_received' => $_SERVER['REQUEST_METHOD']]);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
$rawInput = file_get_contents('php://input');
|
|
$input = json_decode($rawInput, true);
|
|
|
|
// Debug logging
|
|
if ($debugMode) {
|
|
error_log("=== SEND MESSAGE DEBUG ===");
|
|
error_log("Method: " . $_SERVER['REQUEST_METHOD']);
|
|
error_log("Content-Type: " . ($_SERVER['CONTENT_TYPE'] ?? 'not set'));
|
|
error_log("Raw input: " . $rawInput);
|
|
error_log("Parsed JSON: " . json_encode($input));
|
|
error_log("========================");
|
|
}
|
|
|
|
if (!$input) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'JSON inválido o vacío', 'raw_input' => $rawInput]);
|
|
exit;
|
|
}
|
|
|
|
$db = Database::getInstance();
|
|
|
|
// Modo debug: simular envío exitoso
|
|
if ($debugMode) {
|
|
$recipient = $input['recipient'] ?? $input['user_id'] ?? 'unknown';
|
|
$message = $input['message'] ?? 'mensaje de prueba';
|
|
$type = $input['type'] ?? 'text';
|
|
$template = $input['template'] ?? $input['template_name'] ?? null;
|
|
|
|
$responseData = [
|
|
'recipient' => $recipient,
|
|
'type' => $type,
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
|
'warning' => 'Para envío real, verifica que el usuario haya respondido en las últimas 24h o usa plantillas'
|
|
];
|
|
|
|
if ($type === 'template') {
|
|
// Detectar formato de plantilla
|
|
if (isset($input['template']) && is_array($input['template'])) {
|
|
// Formato WhatsApp estándar
|
|
$templateData = $input['template'];
|
|
$responseData['template_name'] = $templateData['name'] ?? 'unknown';
|
|
$responseData['language'] = $templateData['language']['code'] ?? 'es';
|
|
$responseData['format'] = 'whatsapp_standard';
|
|
$message = "Plantilla WhatsApp: {$templateData['name']}";
|
|
} else {
|
|
// Formato simple
|
|
$template = $input['template'] ?? $input['template_name'] ?? null;
|
|
$responseData['template_name'] = $template;
|
|
$responseData['language'] = $input['language'] ?? 'es';
|
|
$responseData['format'] = 'simple';
|
|
$message = "Plantilla: {$template}";
|
|
}
|
|
} else {
|
|
$responseData['message'] = $message;
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'message' => 'Mensaje simulado enviado correctamente (modo debug) - NOTA: En producción, usa plantillas para números que no han respondido en 24h',
|
|
'data' => $responseData
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
|
|
// Modo 1: Envío directo a número de teléfono (formato original)
|
|
if (isset($input['recipient'])) {
|
|
$recipient = $input['recipient'];
|
|
$type = $input['type'] ?? 'text';
|
|
|
|
// Verificar si es mensaje de texto y si el usuario respondió en las últimas 24h
|
|
if ($type === 'text') {
|
|
// Permitir número específico que sí ha respondido
|
|
if ($recipient === '573168950803') {
|
|
// Este número específico tiene permitido envío de texto libre
|
|
error_log("NÚMERO AUTORIZADO: 573168950803 - Permitiendo envío de texto libre");
|
|
} else {
|
|
// Primero obtener el user_id del teléfono
|
|
$userStmt = $db->query(
|
|
"SELECT id FROM users WHERE phone_number = ? LIMIT 1",
|
|
[$recipient]
|
|
);
|
|
$user = $userStmt->fetch();
|
|
|
|
if ($user) {
|
|
$stmt = $db->query(
|
|
"SELECT MAX(created_at) as last_message FROM conversations
|
|
WHERE user_id = ? AND direction = 'incoming'
|
|
AND created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)",
|
|
[$user['id']]
|
|
);
|
|
$lastMessage = $stmt->fetch();
|
|
|
|
if (!$lastMessage || !$lastMessage['last_message']) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'No se puede enviar mensaje de texto libre. El usuario no ha respondido en las últimas 24 horas.',
|
|
'suggestion' => 'Usa una plantilla pre-aprobada o espera a que el usuario te escriba.',
|
|
'error_code' => 'OUTSIDE_24H_WINDOW'
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
// Si no existe el usuario, permitir envío (se creará automáticamente)
|
|
}
|
|
}
|
|
|
|
$whatsappService = new WhatsAppService();
|
|
$response = null;
|
|
|
|
switch ($type) {
|
|
case 'text':
|
|
if (!isset($input['message']) || empty($input['message'])) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Mensaje requerido']);
|
|
exit;
|
|
}
|
|
// DEBUG: Mostrar datos de envío de mensaje de texto
|
|
error_log("=== DEBUG WHATSAPP TEXT MESSAGE ===");
|
|
error_log("Recipient: " . $recipient);
|
|
error_log("Message: " . $input['message']);
|
|
error_log("Method: sendTextMessage()/sendTextReply()");
|
|
error_log("====================================");
|
|
|
|
// Si viene reply_to, usar reply con contexto
|
|
if (!empty($input['reply_to'])) {
|
|
$replyTo = $input['reply_to'];
|
|
$response = $whatsappService->sendTextReply($recipient, $replyTo, $input['message']);
|
|
} else {
|
|
$response = $whatsappService->sendTextMessage($recipient, $input['message']);
|
|
}
|
|
break;
|
|
|
|
case 'template':
|
|
// Formato 1: Simple (actual)
|
|
if (isset($input['template_name']) || (isset($input['template']) && !is_array($input['template']))) {
|
|
$template = $input['template'] ?? $input['template_name'] ?? '';
|
|
if (empty($template)) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Template requerido']);
|
|
exit;
|
|
}
|
|
$language = $input['language'] ?? 'es';
|
|
$parameters = $input['parameters'] ?? [];
|
|
$componentsSimple = $input['components'] ?? null;
|
|
|
|
// Verificar plantilla en base de datos (opcional)
|
|
$templateRecord = null;
|
|
try {
|
|
$stmt = $db->query(
|
|
"SELECT * FROM message_templates WHERE template_name = ? LIMIT 1",
|
|
[$template]
|
|
);
|
|
$templateRecord = $stmt->fetch();
|
|
} catch (Exception $e) {
|
|
// Si no existe la tabla, continuar sin validación local
|
|
error_log("Template validation skipped: " . $e->getMessage());
|
|
}
|
|
|
|
// Solo validar si la tabla existe y encontramos registros
|
|
if ($templateRecord && $templateRecord['status'] !== 'approved') {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Plantilla no aprobada en el sistema local',
|
|
'template_name' => $template,
|
|
'template_status' => $templateRecord['status'],
|
|
'suggestions' => [
|
|
'1. Aprueba la plantilla desde la pestaña Plantillas',
|
|
'2. O verifica que esté aprobada en WhatsApp Business Manager',
|
|
'3. Usa el nombre exacto de la plantilla'
|
|
]
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// Usar el idioma de la base de datos si no se especifica
|
|
if ($language === 'es' && $templateRecord['language_code']) {
|
|
$language = $templateRecord['language_code'];
|
|
}
|
|
|
|
// DEBUG: Mostrar datos de envío de plantilla formato simple
|
|
error_log("=== DEBUG WHATSAPP TEMPLATE MESSAGE (SIMPLE FORMAT) ===");
|
|
error_log("Recipient: " . $recipient);
|
|
error_log("Template Name: " . $template);
|
|
error_log("Language: " . $language);
|
|
error_log("Parameters: " . json_encode($parameters));
|
|
error_log("Template Record Status: " . ($templateRecord ? $templateRecord['status'] : 'not found in DB'));
|
|
error_log("Method: sendTemplateMessage()");
|
|
error_log("========================================================");
|
|
|
|
// Intentar envío y, si falla por traducción no encontrada, probar variantes de idioma
|
|
try {
|
|
$response = $whatsappService->sendTemplateMessage($recipient, $template, $language, $parameters, [], $componentsSimple);
|
|
} catch (Exception $e) {
|
|
$message = $e->getMessage();
|
|
|
|
if (strpos($message, 'Template name does not exist in the translation') !== false || strpos($message, '#132001') !== false) {
|
|
error_log("Template translation missing for language: $language. Attempting fallbacks...");
|
|
|
|
$candidates = [];
|
|
|
|
// Añadir language_code de la BD si existe y es distinto
|
|
if (!empty($templateRecord['language_code']) && $templateRecord['language_code'] !== $language) {
|
|
$candidates[] = $templateRecord['language_code'];
|
|
}
|
|
|
|
// Si viene con formato regional (es_ES) intentar la base (es)
|
|
if (strpos($language, '_') !== false) {
|
|
$base = explode('_', $language)[0];
|
|
if ($base !== $language) $candidates[] = $base;
|
|
} else {
|
|
// Si es código corto (es) intentar variantes comunes
|
|
if (strlen($language) === 2) {
|
|
$candidates[] = strtoupper($language) === $language ? $language : $language . '_ES';
|
|
$candidates[] = $language . '_MX';
|
|
$candidates[] = $language . '_PE';
|
|
}
|
|
}
|
|
|
|
// Eliminar duplicados y vacíos
|
|
$candidates = array_values(array_unique(array_filter($candidates)));
|
|
|
|
foreach ($candidates as $cand) {
|
|
try {
|
|
error_log("Retrying template send with language candidate: $cand");
|
|
$response = $whatsappService->sendTemplateMessage($recipient, $template, $cand, $parameters);
|
|
if ($response) {
|
|
error_log("Template send succeeded with fallback language: $cand");
|
|
break;
|
|
}
|
|
} catch (Exception $e2) {
|
|
error_log("Fallback language $cand failed: " . $e2->getMessage());
|
|
// seguir intentando con siguientes candidatos
|
|
}
|
|
}
|
|
|
|
if (empty($response)) {
|
|
// Re-lanzar el error original si no encontramos nada que funcione
|
|
throw $e;
|
|
}
|
|
} else {
|
|
// Re-lanzar si es otro tipo de error
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|
|
// Formato 2: WhatsApp Business API estándar
|
|
elseif (isset($input['template']) && is_array($input['template'])) {
|
|
$templateData = $input['template'];
|
|
$templateName = $templateData['name'] ?? '';
|
|
$languageCode = $templateData['language']['code'] ?? 'es';
|
|
$components = $templateData['components'] ?? [];
|
|
|
|
if (empty($templateName)) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Template name requerido en formato WhatsApp']);
|
|
exit;
|
|
}
|
|
|
|
// Convertir formato WhatsApp a nuestro servicio
|
|
$parameters = [];
|
|
foreach ($components as $component) {
|
|
if ($component['type'] === 'body' && isset($component['parameters'])) {
|
|
foreach ($component['parameters'] as $param) {
|
|
$parameters[] = $param['text'] ?? '';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Preserve raw components (flow/buttons/header/image) and pass through
|
|
$componentsArray = $templateData['components'] ?? null;
|
|
|
|
// DEBUG: Mostrar datos de envío de plantilla formato WhatsApp estándar
|
|
error_log("=== DEBUG WHATSAPP TEMPLATE MESSAGE (WHATSAPP STANDARD FORMAT) ===");
|
|
error_log("Recipient: " . $recipient);
|
|
error_log("Template Name: " . $templateName);
|
|
error_log("Language Code: " . $languageCode);
|
|
error_log("Original Components: " . json_encode($components));
|
|
error_log("Converted Parameters: " . json_encode($parameters));
|
|
error_log("Full Template Data: " . json_encode($templateData));
|
|
error_log("Method: sendTemplateMessage()");
|
|
error_log("=================================================================");
|
|
|
|
$response = $whatsappService->sendTemplateMessage($recipient, $templateName, $languageCode, $parameters, [], $componentsArray);
|
|
}
|
|
else {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Template requerido (formato simple o WhatsApp estándar)']);
|
|
exit;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Tipo de mensaje no soportado']);
|
|
exit;
|
|
}
|
|
|
|
if ($response) {
|
|
// DEBUG: Mostrar respuesta exitosa de WhatsApp
|
|
error_log("=== DEBUG WHATSAPP SUCCESS RESPONSE ===");
|
|
error_log("Response: " . json_encode($response));
|
|
error_log("======================================");
|
|
|
|
// Guardar mensaje en la base de datos
|
|
try {
|
|
// Buscar o crear usuario por teléfono
|
|
$stmt = $db->query(
|
|
"SELECT id FROM users WHERE phone_number = ? LIMIT 1",
|
|
[$recipient]
|
|
);
|
|
$user = $stmt->fetch();
|
|
|
|
$userId = null;
|
|
if ($user) {
|
|
$userId = $user['id'];
|
|
} else {
|
|
// Crear nuevo usuario
|
|
$stmt = $db->query(
|
|
"INSERT INTO users (phone_number, name, created_at) VALUES (?, ?, NOW())",
|
|
[$recipient, $recipient]
|
|
);
|
|
$userId = $stmt ? $db->lastInsertId() : null;
|
|
}
|
|
|
|
if ($userId) {
|
|
// Preparar datos del mensaje
|
|
$messageContent = '';
|
|
$messageType = $type;
|
|
|
|
if ($type === 'text') {
|
|
$messageContent = $input['message'];
|
|
} elseif ($type === 'template') {
|
|
$templateName = $input['template'] ?? $input['template_name'] ?? '';
|
|
$messageContent = "Plantilla: {$templateName}";
|
|
}
|
|
|
|
// Guardar en la tabla conversations
|
|
$stmt = $db->query(
|
|
"INSERT INTO conversations (user_id, content, direction, message_type, status, message_id, created_at) VALUES (?, ?, 'outgoing', ?, 'sent', ?, NOW())",
|
|
[$userId, $messageContent, $messageType, $response['messages'][0]['id'] ?? null]
|
|
);
|
|
|
|
error_log("Mensaje guardado en BD - User ID: $userId, Content: $messageContent");
|
|
} else {
|
|
error_log("Error: No se pudo obtener o crear user_id para recipient: $recipient");
|
|
}
|
|
} catch (Exception $e) {
|
|
error_log("Error detallado guardando mensaje en base de datos: " . $e->getMessage());
|
|
error_log("Stack trace: " . $e->getTraceAsString());
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'message' => 'Mensaje enviado correctamente',
|
|
'whatsapp_response' => $response
|
|
]);
|
|
} else {
|
|
// DEBUG: Mostrar error de respuesta de WhatsApp
|
|
error_log("=== DEBUG WHATSAPP ERROR RESPONSE ===");
|
|
error_log("Response was NULL or FALSE");
|
|
error_log("Type: " . $type);
|
|
error_log("====================================");
|
|
|
|
// Error específico para plantillas con soluciones detalladas
|
|
if ($type === 'template') {
|
|
$templateName = $input['template_name'] ?? $input['template'] ?? 'unknown';
|
|
$language = $input['language'] ?? 'es';
|
|
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Error #132001: Template name does not exist in the translation',
|
|
'template_name' => $templateName,
|
|
'language' => $language,
|
|
'error_analysis' => [
|
|
'El error #132001 indica que WhatsApp no encuentra la plantilla',
|
|
'Esto puede suceder por varias razones:'
|
|
],
|
|
'solutions' => [
|
|
'1. CREAR PLANTILLA: Ve a WhatsApp Business Manager → Account Tools → Message Templates',
|
|
'2. APROBAR PLANTILLA: Asegúrate que Meta haya aprobado tu plantilla',
|
|
'3. NOMBRE EXACTO: Usa el nombre exacto (case-sensitive)',
|
|
'4. IDIOMA CORRECTO: Usa el código exacto (en_US, es_ES, etc.)',
|
|
'5. TIEMPO DE PROPAGACIÓN: Espera 15-30 min después de la aprobación'
|
|
],
|
|
'debug_info' => [
|
|
'template_attempted' => $templateName,
|
|
'language_attempted' => $language,
|
|
'common_templates' => ['hello_world', 'sample_shipping_confirmation'],
|
|
'common_languages' => ['en_US', 'es_ES', 'es_MX']
|
|
],
|
|
'next_steps' => [
|
|
'1. Verifica en WhatsApp Business Manager si la plantilla existe',
|
|
'2. Crea una plantilla simple primero (ej: "hello_world")',
|
|
'3. Usa el modo debug para probar sin envío real'
|
|
]
|
|
]);
|
|
} else {
|
|
http_response_code(500);
|
|
echo json_encode(['error' => 'Error enviando mensaje']);
|
|
}
|
|
}
|
|
|
|
// Modo 2: Envío a usuario existente (nuevo formato para conversaciones)
|
|
} elseif (isset($input['user_id']) && isset($input['message'])) {
|
|
$userId = intval($input['user_id']);
|
|
$message = trim($input['message']);
|
|
|
|
if (!$userId || !$message) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'user_id y message son requeridos']);
|
|
exit;
|
|
}
|
|
|
|
// Obtener información del usuario
|
|
$stmt = $db->query(
|
|
"SELECT phone_number, name FROM users WHERE id = ?",
|
|
[$userId]
|
|
);
|
|
$user = $stmt->fetch();
|
|
|
|
if (!$user) {
|
|
http_response_code(404);
|
|
echo json_encode(['error' => 'Usuario no encontrado']);
|
|
exit;
|
|
}
|
|
|
|
// Enviar mensaje via WhatsApp API
|
|
$whatsappService = new WhatsAppService();
|
|
|
|
// DEBUG: Mostrar datos de envío a usuario existente
|
|
error_log("=== DEBUG WHATSAPP MESSAGE TO EXISTING USER ===");
|
|
error_log("User ID: " . $userId);
|
|
error_log("User Name: " . ($user['name'] ?? 'N/A'));
|
|
error_log("Phone Number: " . $user['phone_number']);
|
|
error_log("Message: " . $message);
|
|
error_log("Method: sendTextMessage()");
|
|
error_log("===============================================");
|
|
|
|
$response = $whatsappService->sendTextMessage($user['phone_number'], $message);
|
|
|
|
if ($response && isset($response['messages']) && !empty($response['messages'])) {
|
|
// Guardar mensaje en la base de datos
|
|
$messageData = [
|
|
'user_id' => $userId,
|
|
'content' => $message,
|
|
'direction' => 'outgoing',
|
|
'message_type' => 'text',
|
|
'status' => 'sent',
|
|
'message_id' => $response['messages'][0]['id'] ?? null,
|
|
'created_at' => date('Y-m-d H:i:s')
|
|
];
|
|
|
|
// Intentar insertar en conversations primero
|
|
try {
|
|
$stmt = $db->query(
|
|
"INSERT INTO conversations (user_id, content, direction, message_type, status, message_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
array_values($messageData)
|
|
);
|
|
} catch (Exception $e) {
|
|
// Si falla, intentar en messages
|
|
try {
|
|
$stmt = $db->query(
|
|
"INSERT INTO messages (user_id, message_text, direction, message_type, status, message_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
[$userId, $message, 'outgoing', 'text', 'sent', $response['messages'][0]['id'] ?? null, date('Y-m-d H:i:s')]
|
|
);
|
|
} catch (Exception $e2) {
|
|
error_log("Error guardando mensaje: " . $e2->getMessage());
|
|
}
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'message' => 'Mensaje enviado correctamente',
|
|
'whatsapp_response' => $response
|
|
]);
|
|
} else {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Error al enviar mensaje por WhatsApp'
|
|
]);
|
|
}
|
|
|
|
} else {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Formato de datos inválido. Se requiere recipient o user_id+message']);
|
|
exit;
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Error in send_message.php: " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode(['error' => 'Error interno del servidor: ' . $e->getMessage()]);
|
|
}
|
|
?>
|