mail_message.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import logging
  2. import requests
  3. from odoo import models
  4. from odoo.addons.mail.tools.discuss import Store
  5. from odoo.addons.whatsapp.tools.whatsapp_exception import WhatsAppError
  6. from odoo.exceptions import UserError
  7. _logger = logging.getLogger(__name__)
  8. class MailMessage(models.Model):
  9. _inherit = "mail.message"
  10. def _message_reaction(self, content, action, partner, guest, store: Store = None):
  11. """Sobrescribir para usar WhatsApp Web API Gateway cuando esté configurado"""
  12. # Si es mensaje de WhatsApp, verificar si usa WhatsApp Web
  13. if self.message_type == "whatsapp_message" and self.wa_message_ids:
  14. wa_msg = self.wa_message_ids[0]
  15. # Verificar si la cuenta usa WhatsApp Web
  16. if wa_msg.wa_account_id and wa_msg.wa_account_id.whatsapp_web_url:
  17. # Usar API Gateway para WhatsApp Web
  18. self._send_whatsapp_web_reaction(
  19. wa_msg, content, action, partner, guest, store
  20. )
  21. # Actualizar UI directamente usando el método base de mail (sin pasar por enterprise)
  22. # Esto evita que el método del enterprise intente enviar de nuevo
  23. return self._update_reaction_ui(content, action, partner, guest, store)
  24. else:
  25. # Usar método original para WhatsApp Business API (enterprise)
  26. # Este llamará a super() al final para actualizar la UI
  27. return super()._message_reaction(content, action, partner, guest, store)
  28. # Para mensajes que no son de WhatsApp, usar método base
  29. return super()._message_reaction(content, action, partner, guest, store)
  30. def _update_reaction_ui(self, content, action, partner, guest, store: Store = None):
  31. """Actualizar la UI de reacciones sin intentar enviar (para WhatsApp Web)"""
  32. self.ensure_one()
  33. # Buscar reacción existente
  34. domain = [
  35. ("message_id", "=", self.id),
  36. ("partner_id", "=", partner.id),
  37. ("guest_id", "=", guest.id),
  38. ("content", "=", content),
  39. ]
  40. reaction = self.env["mail.message.reaction"].search(domain)
  41. # Crear/eliminar reacción según la acción
  42. if action == "add" and not reaction:
  43. create_values = {
  44. "message_id": self.id,
  45. "content": content,
  46. "partner_id": partner.id,
  47. "guest_id": guest.id,
  48. }
  49. self.env["mail.message.reaction"].create(create_values)
  50. if action == "remove" and reaction:
  51. reaction.unlink()
  52. if store:
  53. # Llenar el store para usuarios portal no autenticados
  54. self._reaction_group_to_store(store, content)
  55. # Enviar el grupo de reacciones al bus para usuarios autenticados
  56. self._bus_send_reaction_group(content)
  57. def _send_whatsapp_web_reaction(
  58. self, wa_msg, content, action, partner, guest, store: Store = None
  59. ):
  60. """Enviar reacción usando WhatsApp Web API Gateway"""
  61. self.ensure_one()
  62. account = wa_msg.wa_account_id
  63. url = account.whatsapp_web_url
  64. session_name = account.whatsapp_web_login
  65. api_key = account.whatsapp_web_api_key
  66. if not all([url, session_name, api_key]):
  67. raise UserError(
  68. "WhatsApp Web no está completamente configurado. Faltan URL, Login o API Key."
  69. )
  70. # Manejar reacciones previas (igual que el método original)
  71. if action == "add":
  72. previous_reaction = self.env["mail.message.reaction"].search(
  73. [
  74. ("message_id", "=", self.id),
  75. ("partner_id", "=", partner.id),
  76. ("guest_id", "=", guest.id),
  77. ],
  78. limit=1,
  79. )
  80. if previous_reaction:
  81. previous_reaction_emoji = previous_reaction.content
  82. if previous_reaction_emoji == content:
  83. return
  84. previous_reaction.unlink()
  85. self._bus_send_reaction_group(previous_reaction_emoji)
  86. # Obtener el ID del mensaje original
  87. message_id = wa_msg.msg_uid
  88. if not message_id:
  89. raise UserError(
  90. "No se puede enviar reacción: el mensaje no tiene ID válido."
  91. )
  92. # Obtener el ID del mensaje original
  93. message_id = wa_msg.msg_uid
  94. if not message_id:
  95. raise UserError(
  96. "No se puede enviar reacción: el mensaje no tiene ID válido."
  97. )
  98. _logger.info(
  99. "DEBUG REACTION - Message Info: ID=%s, Body=%s, State=%s, Type=%s",
  100. message_id,
  101. wa_msg.body,
  102. wa_msg.state,
  103. wa_msg.message_type,
  104. )
  105. # Construir URL y payload para la API Gateway
  106. base_url = url.rstrip("/")
  107. endpoint = "react-message"
  108. full_url = f"{base_url}/api/v1/{session_name}/{endpoint}"
  109. # Determinar emoji (vacío si es remover)
  110. emoji = content if action == "add" else ""
  111. payload = {"msgId": message_id, "reaction": emoji}
  112. headers = {"Content-Type": "application/json", "X-API-Key": api_key}
  113. try:
  114. _logger.info(
  115. "Enviando reacción %s al mensaje %s", emoji or "vacía", message_id
  116. )
  117. response = requests.post(
  118. full_url, json=payload, headers=headers, timeout=30
  119. )
  120. if response.status_code == 200:
  121. _logger.info("Reacción enviada exitosamente a WhatsApp Web")
  122. # No retornar aquí, dejar que el método padre actualice la UI
  123. return
  124. else:
  125. error_text = response.text
  126. _logger.error(
  127. "Error al enviar reacción. Código: %s, Respuesta: %s",
  128. response.status_code,
  129. error_text,
  130. )
  131. raise UserError(f"Error al enviar reacción: {error_text}")
  132. except requests.exceptions.RequestException as e:
  133. _logger.error("Error de conexión al enviar reacción: %s", str(e))
  134. raise UserError(f"Error de conexión al enviar reacción: {str(e)}")
  135. except Exception as e:
  136. _logger.error("Error inesperado al enviar reacción: %s", str(e))
  137. raise UserError(f"Error al enviar reacción: {str(e)}")