from odoo import models, fields, api import logging from datetime import datetime _logger = logging.getLogger(__name__) class WWGroup(models.Model): _name = 'ww.group' _description = 'Grupo de WhatsApp Web' name = fields.Char(string='Nombre del Grupo', required=True) whatsapp_web_id = fields.Char(string='ID WhatsApp Web', index=True, help='ID único del grupo en WhatsApp Web') whatsapp_account_id = fields.Many2one('whatsapp.account', string='Cuenta de WhatsApp', required=True) channel_id = fields.Many2one('discuss.channel', string='Canal de Discusión', readonly=True) contact_ids = fields.Many2many( comodel_name='res.partner', relation='ww_group_contact_rel', column1='group_id', column2='contact_id', string='Contactos', readonly=True, ) def _process_messages(self, messages_data): """Process WhatsApp messages and create them in the channel""" self.ensure_one() if not messages_data or not self.channel_id: return True # Get existing message IDs to avoid duplicates existing_ids = set(self.channel_id.message_ids.mapped('message_id')) # Prepare bulk create values message_vals_list = [] for msg_data in messages_data: msg_id = msg_data.get('id', {}).get('_serialized') # Skip if message already exists if msg_id in existing_ids: continue # Get author partner author_whatsapp_id = msg_data.get('author') author = self.env['res.partner'].search([ ('whatsapp_web_id', '=', author_whatsapp_id) ], limit=1) if author_whatsapp_id else False # Get quoted message author if exists quoted_author = False if msg_data.get('hasQuotedMsg') and msg_data.get('quotedParticipant'): quoted_author = self.env['res.partner'].search([ ('whatsapp_web_id', '=', msg_data['quotedParticipant']) ], limit=1) # Convert timestamp to datetime timestamp = datetime.fromtimestamp(msg_data.get('timestamp', 0)) # Prepare message body with author and content author_name = author.name if author else "Desconocido" message_body = f"{msg_data.get('body', '')}" # Add quoted message if exists if msg_data.get('hasQuotedMsg') and msg_data.get('quotedMsg', {}).get('body'): quoted_author_name = quoted_author.name if quoted_author else "Desconocido" message_body += f"\n\n
{quoted_author_name}: {msg_data['quotedMsg']['body']}
" message_vals = { 'model': 'discuss.channel', 'res_id': self.channel_id.id, 'message_type': 'comment', 'subtype_id': self.env.ref('mail.mt_comment').id, 'body': message_body, 'date': timestamp, 'author_id': author.id if author else self.env.user.partner_id.id, 'message_id': msg_id, } message_vals_list.append(message_vals) # Bulk create messages if message_vals_list: self.env['mail.message'].create(message_vals_list) return True def _create_discussion_channel(self): """Create a discussion channel for the WhatsApp group""" self.ensure_one() try: # Verificar si ya existe un canal para este grupo if self.channel_id: return self.channel_id # Create channel name with WhatsApp prefix channel_name = f"📱 {self.name}" # Verificar que hay contactos if not self.contact_ids: _logger.warning(f"No hay contactos para crear el canal del grupo {self.name}") return False # Obtener los IDs de los contactos de forma segura partner_ids = [] for contact in self.contact_ids: if contact and contact.id: partner_ids.append(contact.id) if not partner_ids: _logger.warning(f"No se encontraron IDs válidos de contactos para el grupo {self.name}") return False # Create the channel using channel_create channel = self.env['discuss.channel'].channel_create( name=channel_name, group_id=self.env.user.groups_id[0].id, # Usar el primer grupo del usuario actual ) # Add members to the channel channel.add_members(partner_ids=partner_ids) # Link the channel to the group self.write({'channel_id': channel.id}) return channel except Exception as e: _logger.error(f"Error al crear el canal para el grupo {self.name}: {str(e)}") return False def _update_discussion_channel(self): """Update the discussion channel members""" self.ensure_one() try: # Si no existe el canal, intentar crearlo if not self.channel_id: return self._create_discussion_channel() # Verificar que el canal aún existe channel = self.env['discuss.channel'].browse(self.channel_id.id) if not channel.exists(): _logger.warning(f"El canal para el grupo {self.name} ya no existe, creando uno nuevo") self.write({'channel_id': False}) return self._create_discussion_channel() # Obtener los IDs de los contactos de forma segura partner_ids = [] for contact in self.contact_ids: if contact and contact.id: partner_ids.append(contact.id) if not partner_ids: _logger.warning(f"No hay contactos válidos para actualizar el canal del grupo {self.name}") return channel # Update channel members using add_members channel.add_members(partner_ids=partner_ids) return channel except Exception as e: _logger.error(f"Error al actualizar el canal para el grupo {self.name}: {str(e)}") return False @api.model def sync_ww_contacts_groups(self): """ Sincroniza los contactos y grupos de WhatsApp Web. Solo sincroniza contactos que están dentro de grupos y valida que no se dupliquen, verificando los últimos 10 dígitos del campo mobile. """ accounts = self.env['whatsapp.account'].search([]) for account in accounts: try: # Obtener grupos usando el método de la cuenta groups_data = account.get_groups() if not groups_data: continue # Procesar cada grupo for group_data in groups_data: group_id = group_data.get('id').get('_serialized') group_name = group_data.get('name', 'Sin nombre') # Buscar o crear grupo group = self.search([ ('whatsapp_web_id', '=', group_id), ('whatsapp_account_id', '=', account.id) ], limit=1) if not group: group = self.create({ 'name': group_name, 'whatsapp_web_id': group_id, 'whatsapp_account_id': account.id }) # Create discussion channel for new group group._create_discussion_channel() else: # Actualizar nombre del grupo si cambió if group.name != group_name: group.write({'name': group_name}) # Actualizar nombre del canal si existe if group.channel_id: group.channel_id.write({'name': f"📱 {group_name}"}) # Procesar participantes del grupo participants = group_data.get('members', []) contact_ids = [] for participant in participants: whatsapp_web_id = participant.get('id', {}).get('_serialized') mobile = participant.get('number', '') is_admin = participant.get('isAdmin', False) is_super_admin = participant.get('isSuperAdmin', False) # Derive participant name participant_name = participant.get('name') or participant.get('pushname') or mobile # Search for existing contact contact = self.env['res.partner'].search([ ('whatsapp_web_id', '=', whatsapp_web_id) ], limit=1) if not contact and mobile and len(mobile) >= 10: last_10_digits = mobile[-10:] contact = self.env['res.partner'].search([ ('mobile', 'like', '%' + last_10_digits) ], limit=1) partner_vals = { 'name': participant_name, 'mobile': mobile, 'whatsapp_web_id': whatsapp_web_id, } if contact: # Update existing contact contact.write(partner_vals) else: # Create new contact contact = self.env['res.partner'].create(partner_vals) if contact: contact_ids.append(contact.id) # Actualizar contactos del grupo group.write({'contact_ids': [(6, 0, contact_ids)]}) # Update discussion channel members group._update_discussion_channel() # Process messages if available messages = group_data.get('messages', []) if messages: group._process_messages(messages) except Exception as e: _logger.error("Error en la sincronización de grupos para la cuenta %s: %s", account.name, str(e)) continue return True