|
|
@@ -0,0 +1,130 @@
|
|
|
+import logging
|
|
|
+import requests
|
|
|
+from odoo import models
|
|
|
+from odoo.addons.mail.tools.discuss import Store
|
|
|
+from odoo.addons.whatsapp.tools.whatsapp_exception import WhatsAppError
|
|
|
+from odoo.exceptions import UserError
|
|
|
+
|
|
|
+_logger = logging.getLogger(__name__)
|
|
|
+
|
|
|
+class MailMessage(models.Model):
|
|
|
+ _inherit = 'mail.message'
|
|
|
+
|
|
|
+ def _message_reaction(self, content, action, partner, guest, store: Store = None):
|
|
|
+ """Sobrescribir para usar WhatsApp Web API Gateway cuando esté configurado"""
|
|
|
+ # Si es mensaje de WhatsApp, verificar si usa WhatsApp Web
|
|
|
+ if self.message_type == "whatsapp_message" and self.wa_message_ids:
|
|
|
+ wa_msg = self.wa_message_ids[0]
|
|
|
+
|
|
|
+ # Verificar si la cuenta usa WhatsApp Web
|
|
|
+ if wa_msg.wa_account_id and wa_msg.wa_account_id.whatsapp_web_url:
|
|
|
+ # Usar API Gateway para WhatsApp Web
|
|
|
+ self._send_whatsapp_web_reaction(wa_msg, content, action, partner, guest, store)
|
|
|
+ # Actualizar UI directamente usando el método base de mail (sin pasar por enterprise)
|
|
|
+ # Esto evita que el método del enterprise intente enviar de nuevo
|
|
|
+ return self._update_reaction_ui(content, action, partner, guest, store)
|
|
|
+ else:
|
|
|
+ # Usar método original para WhatsApp Business API (enterprise)
|
|
|
+ # Este llamará a super() al final para actualizar la UI
|
|
|
+ return super()._message_reaction(content, action, partner, guest, store)
|
|
|
+
|
|
|
+ # Para mensajes que no son de WhatsApp, usar método base
|
|
|
+ return super()._message_reaction(content, action, partner, guest, store)
|
|
|
+
|
|
|
+ def _update_reaction_ui(self, content, action, partner, guest, store: Store = None):
|
|
|
+ """Actualizar la UI de reacciones sin intentar enviar (para WhatsApp Web)"""
|
|
|
+ self.ensure_one()
|
|
|
+ # Buscar reacción existente
|
|
|
+ domain = [
|
|
|
+ ("message_id", "=", self.id),
|
|
|
+ ("partner_id", "=", partner.id),
|
|
|
+ ("guest_id", "=", guest.id),
|
|
|
+ ("content", "=", content),
|
|
|
+ ]
|
|
|
+ reaction = self.env["mail.message.reaction"].search(domain)
|
|
|
+ # Crear/eliminar reacción según la acción
|
|
|
+ if action == "add" and not reaction:
|
|
|
+ create_values = {
|
|
|
+ "message_id": self.id,
|
|
|
+ "content": content,
|
|
|
+ "partner_id": partner.id,
|
|
|
+ "guest_id": guest.id,
|
|
|
+ }
|
|
|
+ self.env["mail.message.reaction"].create(create_values)
|
|
|
+ if action == "remove" and reaction:
|
|
|
+ reaction.unlink()
|
|
|
+ if store:
|
|
|
+ # Llenar el store para usuarios portal no autenticados
|
|
|
+ self._reaction_group_to_store(store, content)
|
|
|
+ # Enviar el grupo de reacciones al bus para usuarios autenticados
|
|
|
+ self._bus_send_reaction_group(content)
|
|
|
+
|
|
|
+ def _send_whatsapp_web_reaction(self, wa_msg, content, action, partner, guest, store: Store = None):
|
|
|
+ """Enviar reacción usando WhatsApp Web API Gateway"""
|
|
|
+ self.ensure_one()
|
|
|
+
|
|
|
+ account = wa_msg.wa_account_id
|
|
|
+ url = account.whatsapp_web_url
|
|
|
+ session_name = account.whatsapp_web_login
|
|
|
+ api_key = account.whatsapp_web_api_key
|
|
|
+
|
|
|
+ if not all([url, session_name, api_key]):
|
|
|
+ raise UserError("WhatsApp Web no está completamente configurado. Faltan URL, Login o API Key.")
|
|
|
+
|
|
|
+ # Manejar reacciones previas (igual que el método original)
|
|
|
+ if action == "add":
|
|
|
+ previous_reaction = self.env["mail.message.reaction"].search([
|
|
|
+ ("message_id", "=", self.id),
|
|
|
+ ("partner_id", "=", partner.id),
|
|
|
+ ("guest_id", "=", guest.id),
|
|
|
+ ], limit=1)
|
|
|
+ if previous_reaction:
|
|
|
+ previous_reaction_emoji = previous_reaction.content
|
|
|
+ if previous_reaction_emoji == content:
|
|
|
+ return
|
|
|
+ previous_reaction.unlink()
|
|
|
+ self._bus_send_reaction_group(previous_reaction_emoji)
|
|
|
+
|
|
|
+ # Obtener el ID del mensaje original
|
|
|
+ message_id = wa_msg.msg_uid
|
|
|
+ if not message_id:
|
|
|
+ raise UserError("No se puede enviar reacción: el mensaje no tiene ID válido.")
|
|
|
+
|
|
|
+ # Construir URL y payload para la API Gateway
|
|
|
+ base_url = url.rstrip('/')
|
|
|
+ endpoint = 'send-reaction'
|
|
|
+ full_url = f"{base_url}/api/v1/{session_name}/{endpoint}"
|
|
|
+
|
|
|
+ # Determinar emoji (vacío si es remover)
|
|
|
+ emoji = content if action == "add" else ""
|
|
|
+
|
|
|
+ payload = {
|
|
|
+ "messageId": message_id,
|
|
|
+ "emoji": emoji
|
|
|
+ }
|
|
|
+
|
|
|
+ headers = {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "X-API-Key": api_key
|
|
|
+ }
|
|
|
+
|
|
|
+ try:
|
|
|
+ _logger.info("Enviando reacción %s al mensaje %s", emoji or "vacía", message_id)
|
|
|
+ response = requests.post(full_url, json=payload, headers=headers, timeout=30)
|
|
|
+
|
|
|
+ if response.status_code == 200:
|
|
|
+ _logger.info("Reacción enviada exitosamente a WhatsApp Web")
|
|
|
+ # No retornar aquí, dejar que el método padre actualice la UI
|
|
|
+ return
|
|
|
+ else:
|
|
|
+ error_text = response.text
|
|
|
+ _logger.error("Error al enviar reacción. Código: %s, Respuesta: %s", response.status_code, error_text)
|
|
|
+ raise UserError(f"Error al enviar reacción: {error_text}")
|
|
|
+
|
|
|
+ except requests.exceptions.RequestException as e:
|
|
|
+ _logger.error("Error de conexión al enviar reacción: %s", str(e))
|
|
|
+ raise UserError(f"Error de conexión al enviar reacción: {str(e)}")
|
|
|
+ except Exception as e:
|
|
|
+ _logger.error("Error inesperado al enviar reacción: %s", str(e))
|
|
|
+ raise UserError(f"Error al enviar reacción: {str(e)}")
|
|
|
+
|