|
@@ -3,6 +3,7 @@ import requests
|
|
|
import json
|
|
import json
|
|
|
import mimetypes
|
|
import mimetypes
|
|
|
import base64
|
|
import base64
|
|
|
|
|
+import traceback
|
|
|
from markupsafe import Markup
|
|
from markupsafe import Markup
|
|
|
|
|
|
|
|
from odoo import fields, models, _
|
|
from odoo import fields, models, _
|
|
@@ -21,6 +22,15 @@ class WhatsAppAccount(models.Model):
|
|
|
whatsapp_web_login = fields.Char(string="Login", readonly=False, copy=False)
|
|
whatsapp_web_login = fields.Char(string="Login", readonly=False, copy=False)
|
|
|
whatsapp_web_api_key = fields.Char(string="API Key", readonly=False, copy=False)
|
|
whatsapp_web_api_key = fields.Char(string="API Key", readonly=False, copy=False)
|
|
|
|
|
|
|
|
|
|
+ def _send_message(self, message_type, message_values, message_id):
|
|
|
|
|
+ """Trap to debug who is sending messages"""
|
|
|
|
|
+ _logger.warning(
|
|
|
|
|
+ "TRAP: _send_message called! Type: %s. Stack: \n%s",
|
|
|
|
|
+ message_type,
|
|
|
|
|
+ "".join(traceback.format_stack()),
|
|
|
|
|
+ )
|
|
|
|
|
+ return super()._send_message(message_type, message_values, message_id)
|
|
|
|
|
+
|
|
|
def get_groups(self):
|
|
def get_groups(self):
|
|
|
"""
|
|
"""
|
|
|
Obtiene los grupos de WhatsApp Web para la cuenta desde la base de datos de la plataforma.
|
|
Obtiene los grupos de WhatsApp Web para la cuenta desde la base de datos de la plataforma.
|
|
@@ -150,11 +160,6 @@ class WhatsAppAccount(models.Model):
|
|
|
y rutearlos al chat correcto.
|
|
y rutearlos al chat correcto.
|
|
|
Refactorizado para soportar grupos vía metadata y creación Lazy.
|
|
Refactorizado para soportar grupos vía metadata y creación Lazy.
|
|
|
"""
|
|
"""
|
|
|
- # Log del payload recibido para debug
|
|
|
|
|
- _logger.info(
|
|
|
|
|
- "DEBUG - WhatsApp Webhook Value: %s",
|
|
|
|
|
- json.dumps(value, indent=4, default=str),
|
|
|
|
|
- )
|
|
|
|
|
|
|
|
|
|
if "messages" not in value and value.get("whatsapp_business_api_data", {}).get(
|
|
if "messages" not in value and value.get("whatsapp_business_api_data", {}).get(
|
|
|
"messages"
|
|
"messages"
|
|
@@ -166,6 +171,9 @@ class WhatsAppAccount(models.Model):
|
|
|
# 1. Identificar Remitente (Sender)
|
|
# 1. Identificar Remitente (Sender)
|
|
|
contacts_data = value.get("contacts", [])
|
|
contacts_data = value.get("contacts", [])
|
|
|
sender_partner = self._find_or_create_partner_from_payload(contacts_data)
|
|
sender_partner = self._find_or_create_partner_from_payload(contacts_data)
|
|
|
|
|
+ original_sender_partner = (
|
|
|
|
|
+ sender_partner # Preserve original sender (Me) for attribution
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
# Fallback Name if partner creation failed (rare)
|
|
# Fallback Name if partner creation failed (rare)
|
|
|
sender_name = sender_partner.name if sender_partner else "Unknown"
|
|
sender_name = sender_partner.name if sender_partner else "Unknown"
|
|
@@ -229,6 +237,22 @@ class WhatsAppAccount(models.Model):
|
|
|
sender_mobile,
|
|
sender_mobile,
|
|
|
messages["from"],
|
|
messages["from"],
|
|
|
)
|
|
)
|
|
|
|
|
+
|
|
|
|
|
+ # Fix: Update sender_partner to be the RECIPIENT partner for correct channel naming
|
|
|
|
|
+ if len(sender_mobile) >= 10:
|
|
|
|
|
+ sender_partner = (
|
|
|
|
|
+ self.env["res.partner"]
|
|
|
|
|
+ .sudo()
|
|
|
|
|
+ .search(
|
|
|
|
|
+ [("mobile", "like", f"%{sender_mobile[-10:]}")], limit=1
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ if sender_partner:
|
|
|
|
|
+ _logger.info(
|
|
|
|
|
+ "Partner destinatario encontrado para self-message: %s",
|
|
|
|
|
+ sender_partner.name,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
# --- RECONCILIATION LOGIC ---
|
|
# --- RECONCILIATION LOGIC ---
|
|
|
# Si viene un job_id en metadata, reconciliar el ID antes de chequear duplicados.
|
|
# Si viene un job_id en metadata, reconciliar el ID antes de chequear duplicados.
|
|
|
# Esto maneja el caso donde el "Echo" del mensaje trae el ID real y confirma el envío del worker.
|
|
# Esto maneja el caso donde el "Echo" del mensaje trae el ID real y confirma el envío del worker.
|
|
@@ -363,7 +387,15 @@ class WhatsAppAccount(models.Model):
|
|
|
|
|
|
|
|
# Determinar autor (Author ID)
|
|
# Determinar autor (Author ID)
|
|
|
# Preferimos usar el partner identificado del payload
|
|
# Preferimos usar el partner identificado del payload
|
|
|
- author_id = sender_partner.id if sender_partner else False
|
|
|
|
|
|
|
+ # Si es self-message, usar original_sender_partner (Me)
|
|
|
|
|
+ if is_self_message:
|
|
|
|
|
+ author_id = (
|
|
|
|
|
+ original_sender_partner.id
|
|
|
|
|
+ if original_sender_partner
|
|
|
|
|
+ else self.env.ref("base.partner_root").id
|
|
|
|
|
+ )
|
|
|
|
|
+ else:
|
|
|
|
|
+ author_id = sender_partner.id if sender_partner else False
|
|
|
|
|
|
|
|
# If no sender partner, try channel partner if target is channel
|
|
# If no sender partner, try channel partner if target is channel
|
|
|
if (
|
|
if (
|
|
@@ -372,10 +404,6 @@ class WhatsAppAccount(models.Model):
|
|
|
):
|
|
):
|
|
|
author_id = target_record.whatsapp_partner_id.id
|
|
author_id = target_record.whatsapp_partner_id.id
|
|
|
|
|
|
|
|
- if is_self_message:
|
|
|
|
|
- # Si es mensaje propio, usar el partner de la compañía o OdooBot
|
|
|
|
|
- author_id = self.env.ref("base.partner_root").id
|
|
|
|
|
-
|
|
|
|
|
kwargs = {
|
|
kwargs = {
|
|
|
"message_type": "whatsapp_message",
|
|
"message_type": "whatsapp_message",
|
|
|
"author_id": author_id,
|
|
"author_id": author_id,
|
|
@@ -484,7 +512,6 @@ class WhatsAppAccount(models.Model):
|
|
|
_logger.warning("Unsupported whatsapp message type: %s", messages)
|
|
_logger.warning("Unsupported whatsapp message type: %s", messages)
|
|
|
continue
|
|
continue
|
|
|
|
|
|
|
|
- # Fix: Only pass whatsapp_inbound_msg_uid if valid for this channel type
|
|
|
|
|
# Standard channels (like groups) do not support this param and will crash
|
|
# Standard channels (like groups) do not support this param and will crash
|
|
|
if getattr(target_record, "_name", "") == "discuss.channel":
|
|
if getattr(target_record, "_name", "") == "discuss.channel":
|
|
|
if (
|
|
if (
|