| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- from datetime import datetime, timedelta
- from odoo import models, api, fields
- from odoo.addons.mail.tools.discuss import Store
- from odoo.exceptions import ValidationError
- class DiscussChannel(models.Model):
- _inherit = "discuss.channel"
- is_whatsapp_web = fields.Boolean(compute="_compute_is_whatsapp_web")
- def write(self, vals):
- """
- Override write to debounce 'last_interest_dt' updates.
- 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:
- # Check if we have a recent update
- if self.last_interest_dt:
- # Calculate time since last update
- # Note: last_interest_dt is usually UTC
- 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"]
- return super().write(vals)
- @api.depends("channel_type", "wa_account_id.whatsapp_web_url")
- def _compute_is_whatsapp_web(self):
- for record in self:
- record.is_whatsapp_web = record.channel_type == "whatsapp" and bool(
- record.wa_account_id.whatsapp_web_url
- )
- def _to_store(self, store: Store):
- """
- Send is_whatsapp_web to the frontend via Store.
- """
- super()._to_store(store)
- for channel in self:
- if channel.is_whatsapp_web:
- store.add(channel, {"is_whatsapp_web": True})
- def message_post(self, **kwargs):
- """
- Override message_post to allow sending free text messages in WhatsApp Web channels.
- Standard Odoo WhatsApp module might block or restrict messages without templates.
- """
- # Check if it's a WhatsApp channel with WhatsApp Web configured
- if self.channel_type == "whatsapp" and self.wa_account_id.whatsapp_web_url:
- # We want to use our custom logic for these channels
- # Extract basic message data
- body = kwargs.get("body", "")
- attachment_ids = kwargs.get("attachment_ids", [])
- # If it's a simple text message or has attachments, we handle it.
- # Note: We need to ensure we don't break other message_post usages (like system notifications)
- # System notifications usually have subtype_xmlid='mail.mt_note' or similar, strict check might be needed.
- # Let's check if we should intervene.
- # If the user is trying to send a message (comment)
- if kwargs.get("message_type") == "comment" or not kwargs.get(
- "message_type"
- ):
- # Check for attachments in kwargs (can be list of IDs or list of tuples)
- # We mainly care about passing them to the mail.message
- # 1. Create the mail.message manually to bypass potential blocks in super().message_post()
- # We need to replicate some logic from mail.thread.message_post
- # However, completely skipping super() is risky for notifications/followers.
- # Let's try a hybrid approach:
- # Create the message using mail.message.create() directly, then run necessary side effects?
- # Or invoke mail.thread's message_post directly if possible?
- # We can't easily invoke 'grandparent' methods in Odoo new API unless we are careful.
- # Simplified approach: mimic whatsapp_composer logic
- email_from = kwargs.get("email_from")
- if not email_from:
- email_from = self.env.user.email_formatted
- # Create mail.message
- msg_values = {
- "body": body,
- "model": self._name,
- "res_id": self.id,
- "message_type": "whatsapp_message", # Use whatsapp_message type so our other logic picks it up? Or 'comment'?
- # Standard WA uses 'whatsapp_message'
- "email_from": email_from,
- "partner_ids": [
- (4, p.id) for p in self.channel_partner_ids
- ], # Add channel partners?
- # 'subtype_id': ...
- "attachment_ids": attachment_ids,
- }
- # Handle author
- author_id = kwargs.get("author_id")
- if author_id:
- msg_values["author_id"] = author_id
- else:
- msg_values["author_id"] = self.env.user.partner_id.id
- # Create the message
- message = self.env["mail.message"].create(msg_values)
- # Now create the whatsapp.message to trigger sending (via our overridden _send_message or similar)
- # Note: whatsapp_message.create() triggers _send_message() if state is outgoing?
- # In our whatsapp_composer, we called _send_message() explicitly.
- # Determine recipient (Phone or Group)
- mobile_number = self.whatsapp_number
- recipient_type = "phone"
- if mobile_number and mobile_number.endswith("@g.us"):
- recipient_type = "group"
- wa_msg_values = {
- "mail_message_id": message.id,
- "wa_account_id": self.wa_account_id.id,
- "mobile_number": mobile_number,
- "recipient_type": recipient_type,
- "wa_template_id": False,
- "body": body,
- "state": "outgoing",
- }
- wa_msg = self.env["whatsapp.message"].create(wa_msg_values)
- # Send it
- wa_msg._send_message()
- # Ensure the message is linked to the channel (standard mail.message behavior should handle res_id/model)
- # But Discuss expects the message to be in the channel.
- return message
- # Default behavior for other channels or if conditions not met
- return super(DiscussChannel, self).message_post(**kwargs)
|