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." ) # 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." ) _logger.info( "DEBUG REACTION - Message Info: ID=%s, Body=%s, State=%s, Type=%s", message_id, wa_msg.body, wa_msg.state, wa_msg.message_type, ) # Construir URL y payload para la API Gateway base_url = url.rstrip("/") endpoint = "react-message" full_url = f"{base_url}/api/v1/{session_name}/{endpoint}" # Determinar emoji (vacío si es remover) emoji = content if action == "add" else "" payload = {"msgId": message_id, "reaction": 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)}")