| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- 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)}")
|