| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- 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<blockquote><strong>{quoted_author_name}:</strong> {msg_data['quotedMsg']['body']}</blockquote>"
- 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
|