4
0

3 Commity e53790c888 ... 18a377b2c9

Autor SHA1 Správa Dátum
  odoo 18a377b2c9 Merge remote changes for whatsapp_web 1 mesiac pred
  odoo b4cc0644ee Fix Portal Account 500 Error and UI Refinements 1 mesiac pred
  odoo 93ec3859b8 Fix license warnings and deprecated create methods 1 mesiac pred

+ 1 - 0
__manifest__.py

@@ -24,4 +24,5 @@
     },
     "installable": True,
     "auto_install": False,
+    "license": "LGPL-3",
 }

+ 3 - 3
models/discuss_channel.py

@@ -15,7 +15,7 @@ class DiscussChannel(models.Model):
         If the channel was updated less than 10 seconds ago, skip updating last_interest_dt.
         This prevents 'concurrent update' errors during high traffic (e.g. active WhatsApp groups).
         """
-        if 'last_interest_dt' in vals and len(self) == 1:
+        if "last_interest_dt" in vals and len(self) == 1:
             # Check if we have a recent update
             if self.last_interest_dt:
                 # Calculate time since last update
@@ -23,8 +23,8 @@ class DiscussChannel(models.Model):
                 time_since_last = datetime.now() - self.last_interest_dt
                 if time_since_last < timedelta(seconds=10):
                     # Skip updating this field
-                    del vals['last_interest_dt']
-        
+                    del vals["last_interest_dt"]
+
         return super().write(vals)
 
     @api.depends("channel_type", "wa_account_id.whatsapp_web_url")

+ 63 - 21
models/whatsapp_account.py

@@ -242,6 +242,8 @@ class WhatsAppAccount(models.Model):
             # ---------------------------
 
             # Context / Reply Handling
+            target_record = False
+
             if "context" in messages and messages["context"].get("id"):
                 parent_whatsapp_message = (
                     self.env["whatsapp.message"]
@@ -251,12 +253,34 @@ class WhatsAppAccount(models.Model):
                 if parent_whatsapp_message:
                     parent_msg_id = parent_whatsapp_message.id
                     parent_id = parent_whatsapp_message.mail_message_id
-                if parent_id:
-                    channel = (
-                        self.env["discuss.channel"]
-                        .sudo()
-                        .search([("message_ids", "in", parent_id.id)], limit=1)
-                    )
+
+                    if parent_id:
+                        # Check where the parent message belongs
+                        if (
+                            parent_id.model
+                            and parent_id.model != "discuss.channel"
+                            and parent_id.res_id
+                        ):
+                            # It's a reply to a document (Ticket, Order, etc.)
+                            try:
+                                target_record = self.env[parent_id.model].browse(
+                                    parent_id.res_id
+                                )
+                                _logger.info(
+                                    f"Reply routed to Document: {parent_id.model} #{parent_id.res_id}"
+                                )
+                            except Exception as e:
+                                _logger.warning(
+                                    f"Could not load target record {parent_id.model} #{parent_id.res_id}: {e}"
+                                )
+                                target_record = False
+                        else:
+                            # It's a reply in a channel
+                            channel = (
+                                self.env["discuss.channel"]
+                                .sudo()
+                                .search([("message_ids", "in", parent_id.id)], limit=1)
+                            )
 
             # 2. Lógica de Grupos (Metadata - Decoupled & Lazy)
             group_metadata = value.get("metadata", {}).get("group")
@@ -264,7 +288,7 @@ class WhatsAppAccount(models.Model):
             if not group_metadata and value.get("metadata", {}).get("group_id"):
                 group_metadata = {"id": value.get("metadata", {}).get("group_id")}
 
-            if group_metadata:
+            if group_metadata and not target_record:
                 # Check if group module is installed (Use 'in' operator for models with dots)
                 if "ww.group" in self.env:
                     # Process Group (Lazy Create + Organic Member Add)
@@ -282,16 +306,14 @@ class WhatsAppAccount(models.Model):
                         "Recibido mensaje de grupo pero ww.group no está instalado."
                     )
 
-            # 3. Canal Directo (Si no es grupo)
-            if not channel:
+            # 3. Canal Directo (Si no es grupo y no tenemos target ni channel aun)
+            if not target_record and not channel:
                 channel = self._find_active_channel(
                     sender_mobile, sender_name=sender_name, create_if_not_found=True
                 )
 
             # --- RENAME LOGIC FOR 1:1 CHATS ---
-            # Si el canal es tipo WhatsApp y no es un grupo (no termina en @g.us),
-            # aseguramos que el nombre del canal coincida con el del Partner.
-            # Esto corrige canales con nombres numéricos o "Unknown".
+            # Solo si estamos usando un canal (no si vamos a un documento)
             if channel and channel.channel_type == "whatsapp" and sender_partner:
                 is_group_channel = False
                 if channel.whatsapp_number and channel.whatsapp_number.endswith(
@@ -306,11 +328,24 @@ class WhatsAppAccount(models.Model):
                     channel.sudo().write({"name": sender_partner.name})
             # -----------------------------------
 
+            # Define Target Record if not set (fallback to channel)
+            if not target_record:
+                target_record = channel
+
+            if not target_record:
+                _logger.error("Could not determine target record for message")
+                continue
+
             # Determinar autor (Author ID)
             # Preferimos usar el partner identificado del payload
-            author_id = (
-                sender_partner.id if sender_partner else channel.whatsapp_partner_id.id
-            )
+            author_id = sender_partner.id if sender_partner else False
+
+            # If no sender partner, try channel partner if target is channel
+            if (
+                not author_id
+                and getattr(target_record, "_name", "") == "discuss.channel"
+            ):
+                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
@@ -319,7 +354,6 @@ class WhatsAppAccount(models.Model):
             kwargs = {
                 "message_type": "whatsapp_message",
                 "author_id": author_id,
-                "parent_msg_id": parent_msg_id,
                 "subtype_xmlid": "mail.mt_comment",
                 "parent_id": parent_id.id if parent_id else None,
             }
@@ -409,8 +443,12 @@ class WhatsAppAccount(models.Model):
                                 )
                             )
 
-                    if not partner_id:
-                        partner_id = channel.whatsapp_partner_id
+                    if (
+                        not partner_id
+                        and getattr(target_record, "_name", "") == "discuss.channel"
+                    ):
+                        partner_id = target_record.whatsapp_partner_id
+
                     emoji = messages["reaction"].get("emoji")
                     whatsapp_message.mail_message_id._post_whatsapp_reaction(
                         reaction_content=emoji, partner_id=partner_id
@@ -422,7 +460,11 @@ class WhatsAppAccount(models.Model):
 
             # 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
-            if channel.channel_type == "whatsapp":
-                kwargs["whatsapp_inbound_msg_uid"] = messages["id"]
+            if getattr(target_record, "_name", "") == "discuss.channel":
+                if (
+                    hasattr(target_record, "channel_type")
+                    and target_record.channel_type == "whatsapp"
+                ):
+                    kwargs["whatsapp_inbound_msg_uid"] = messages["id"]
 
-            channel.message_post(**kwargs)
+            target_record.message_post(**kwargs)

+ 16 - 15
models/whatsapp_message.py

@@ -9,6 +9,7 @@ import json
 import re
 import html
 import base64
+from odoo.tools import html2plaintext
 
 _logger = logging.getLogger(__name__)
 
@@ -222,31 +223,31 @@ class WhatsAppMessage(models.Model):
             # no template
             elif whatsapp_message.mail_message_id.attachment_ids:
                 attachment = whatsapp_message.mail_message_id.attachment_ids[0]
+            # Fallback: check parent message attachments (e.g. from Chatter)
+            elif (
+                whatsapp_message.mail_message_id.parent_id
+                and whatsapp_message.mail_message_id.parent_id.attachment_ids
+            ):
+                attachment = whatsapp_message.mail_message_id.parent_id.attachment_ids[
+                    0
+                ]
 
             # codigo para limpiar body y numero
             body = whatsapp_message.body
 
-            # Asegurar que body sea string y limpiar HTML
+            # Asegurar que body sea string y limpiar HTML usando html2plaintext para robustez
             if body:
-                if isinstance(body, markupsafe.Markup):
-                    text = html.unescape(str(body))
-                else:
-                    text = str(body)
-
-                # Reemplazamos las etiquetas BR y P
-                text = re.sub(r"<br\s*/?>|<BR\s*/?>", "\n", text)
-                text = re.sub(r"<p>|<P>", "\n\n", text)
-                text = re.sub(r"</p>|</P>", "", text)
+                # Log raw body to debug inputs
+                _logger.info(f"WHATSAPP RAW BODY Input: {body!r}")
 
-                # Eliminamos el resto de etiquetas HTML
-                text = re.sub(r"<[^>]+>", "", text)
-
-                # Limpiamos múltiples saltos de línea
-                text = re.sub(r"\n\s*\n\s*\n", "\n\n", text)
+                # Use html2plaintext to strip all tags and entities correctly
+                text = html2plaintext(str(body))
 
                 # Limpiamos espacios en blanco al inicio y final
                 body = text.strip()
 
+                _logger.info(f"WHATSAPP CLEAN BODY Output: {body!r}")
+
                 # Asegurar que no esté vacío (solo si no hay adjunto)
                 if not body:
                     body = "" if attachment else "Mensaje de WhatsApp"