فهرست منبع

Migrar a nueva API Gateway: usar session_name y api_key, endpoint groups desde BD

MC Team 4 ماه پیش
والد
کامیت
deb2f0344b
3فایلهای تغییر یافته به همراه142 افزوده شده و 50 حذف شده
  1. 23 9
      models/whatsapp_account.py
  2. 116 38
      models/whatsapp_message.py
  3. 3 3
      views/whatsapp_account_views.xml

+ 23 - 9
models/whatsapp_account.py

@@ -15,9 +15,9 @@ class WhatsAppAccount(models.Model):
 
     def get_groups(self):
         """
-        Obtiene los grupos de WhatsApp Web para la cuenta usando el wrapper HTTP de whatsapp-web.js.
+        Obtiene los grupos de WhatsApp Web para la cuenta desde la base de datos de la plataforma.
         Returns:
-            list: Lista de diccionarios con la información de los grupos
+            list: Lista de diccionarios con la información de los grupos en formato compatible con Odoo
         """
         self.ensure_one()
         
@@ -25,19 +25,33 @@ class WhatsAppAccount(models.Model):
             _logger.warning("No se ha configurado la URL de WhatsApp Web para la cuenta %s", self.name)
             return []
 
+        if not self.whatsapp_web_login:
+            _logger.warning("No se ha configurado el Login (session_name) para la cuenta %s", self.name)
+            return []
+
+        if not self.whatsapp_web_api_key:
+            _logger.warning("No se ha configurado la API Key para la cuenta %s", self.name)
+            return []
+
         try:
-            headers = {"Content-Type": "application/json"}
-            chats_payload = {
-                "method": "getGroups",
-                "args": []
+            # Construir URL del nuevo endpoint
+            base_url = self.whatsapp_web_url.rstrip('/')
+            session_name = self.whatsapp_web_login
+            url = f"{base_url}/api/v1/{session_name}/groups"
+            
+            headers = {
+                "Content-Type": "application/json",
+                "X-API-Key": self.whatsapp_web_api_key
             }
             
-            response = requests.post(self.whatsapp_web_url, data=json.dumps(chats_payload), headers=headers)
+            response = requests.get(url, headers=headers, timeout=30)
+            
             if response.status_code == 200:
-                groups = response.json()                
+                groups = response.json()
+                _logger.info("Grupos obtenidos desde la base de datos: %d grupos", len(groups))
                 return groups
             else:
-                _logger.error("Error al obtener groups: %s", response.text)
+                _logger.error("Error al obtener groups: %s - %s", response.status_code, response.text)
                 return []
                 
         except Exception as e:

+ 116 - 38
models/whatsapp_message.py

@@ -112,15 +112,21 @@ class WhatsAppMessage(models.Model):
     def _send_message(self, with_commit=False):
 
         url = ''
+        session_name = ''
+        api_key = ''
 
         if self.wa_account_id and self.wa_account_id.whatsapp_web_url:
             url = self.wa_account_id.whatsapp_web_url
-            _logger.info('WHATSAPP WEB SEND MESSAGE' + url)
+            session_name = self.wa_account_id.whatsapp_web_login or ''
+            api_key = self.wa_account_id.whatsapp_web_api_key or ''
+            _logger.info('WHATSAPP WEB SEND MESSAGE - URL: %s, Session: %s', url, session_name)
 
         group = ''
         
-        if not url:
+        if not url or not session_name or not api_key:
+            # Si no hay configuración de WhatsApp Web, usar método original
             super()._send_message(with_commit)
+            return
             
         for whatsapp_message in self:
             # Determinar destinatario final usando solo la nueva lógica
@@ -211,18 +217,13 @@ class WhatsAppMessage(models.Model):
                         
                         number = number + '@c.us'
 
-            # ENVIO DE MENSAJE
-            # Headers de la petición, si es necesario
-            headers = {
-                "Content-Type": "application/json"
-            }
-            
-            #$wa::sendMessage("521{$fields_data[$settings['borax_whatsapp_mobile']]}@c.us", ['type' => 'MessageMedia', 'args' => [mime_content_type($file), base64_encode(file_get_contents($file)), $filename, $filesize]], ['caption' => $borax_whatsapp_mensaje]);
+            # ENVIO DE MENSAJE - Nueva API Gateway
             parent_message_id = ''
             if whatsapp_message.mail_message_id and whatsapp_message.mail_message_id.parent_id:
                     parent_id = whatsapp_message.mail_message_id.parent_id.wa_message_ids
                     if parent_id:
                         parent_message_id = parent_id[0].msg_uid
+            
             # Validar que tenemos un destinatario válido
             if not number:
                 _logger.error("No se pudo determinar el destinatario para el mensaje")
@@ -233,43 +234,120 @@ class WhatsAppMessage(models.Model):
                 _logger.error("Cuerpo del mensaje inválido: %s", body)
                 body = "Mensaje de WhatsApp"
             
-            # Log del payload para debugging
-            _logger.info("Enviando mensaje a %s: %s", number, body[:50] + "..." if len(body) > 50 else body)
+            # Determinar si es grupo
+            is_group = number.endswith('@g.us') if number else False
+            
+            # Construir URL base
+            base_url = url.rstrip('/')
+            endpoint = 'send-message'
+            
+            # Headers con autenticación
+            headers = {
+                "Content-Type": "application/json",
+                "X-API-Key": api_key
+            }
             
+            # Preparar payload según tipo de mensaje
             if attachment:
+                # Determinar endpoint según tipo de archivo
+                mimetype = attachment.mimetype or 'application/octet-stream'
+                if mimetype.startswith('image/'):
+                    endpoint = 'send-image'
+                elif mimetype.startswith('video/'):
+                    endpoint = 'send-video'
+                elif mimetype.startswith('audio/'):
+                    endpoint = 'send-voice'
+                else:
+                    endpoint = 'send-file'
+                
+                # Convertir archivo a base64 con prefijo data URI
+                file_base64 = base64.b64encode(attachment.raw).decode('utf-8')
+                base64_with_prefix = f"data:{mimetype};base64,{file_base64}"
+                
                 payload = {
-                    "method": "sendMessage",  
-                    "args": [number, {'type': 'MessageMedia', 'args': [attachment.mimetype, base64.b64encode(attachment.raw).decode('utf-8'), attachment.name, attachment.file_size]}, {'caption': body}]
+                    "phone": [number],  # Array para send-image/send-file
+                    "base64": base64_with_prefix,
+                    "filename": attachment.name or "file",
+                    "caption": body,
+                    "isGroup": is_group
                 }
-            else: 
+                
+                if parent_message_id:
+                    payload["quotedMessageId"] = parent_message_id
+            else:
+                # Mensaje de texto
                 payload = {
-                    "method": "sendMessage",  
-                    "args": [number, body, {}]
+                    "phone": number,  # String para send-message
+                    "message": body,
+                    "isGroup": is_group
                 }
-
-            if parent_message_id:
-                payload['args'][2]['quotedMessageId'] = parent_message_id
-
-            # Realizando la petición POST
-            response = requests.post(url, data=json.dumps(payload), headers=headers)
-
-            # Verificando si la respuesta contiene data->id
-            if response.status_code == 200:
-                try:
-                    response_json = response.json()
-                except ValueError:
-                    _logger.error("La respuesta no es JSON válido: %s", response.text)
-                    response_json = {}
-                if "_data" in response_json and "id" in response_json["_data"]:
-                    _logger.info(f"Petición exitosa. ID: {response_json['_data']['id']['id']}")
+                
+                if parent_message_id:
+                    payload["quotedMessageId"] = parent_message_id
+            
+            # Construir URL completa
+            full_url = f"{base_url}/api/v1/{session_name}/{endpoint}"
+            
+            # Log del payload para debugging
+            _logger.info("Enviando mensaje a %s (%s) usando endpoint %s", number, "grupo" if is_group else "contacto", endpoint)
+            
+            # Realizar petición POST
+            try:
+                response = requests.post(full_url, json=payload, headers=headers, timeout=60)
+                
+                # Procesar respuesta
+                if response.status_code == 200:
+                    try:
+                        response_json = response.json()
+                        
+                        # La nueva API puede devolver jobId (mensaje encolado) o id (enviado directamente)
+                        if 'jobId' in response_json:
+                            # Mensaje encolado
+                            _logger.info("Mensaje encolado. Job ID: %s", response_json.get('jobId'))
+                            whatsapp_message.write({
+                                'state': 'outgoing',  # Mantener 'outgoing' para compatibilidad
+                                'msg_uid': response_json.get('jobId')
+                            })
+                            self._cr.commit()
+                        elif 'id' in response_json:
+                            # Mensaje enviado directamente
+                            msg_id = response_json.get('id')
+                            if isinstance(msg_id, dict) and '_serialized' in msg_id:
+                                msg_uid = msg_id['_serialized']
+                            elif isinstance(msg_id, str):
+                                msg_uid = msg_id
+                            else:
+                                msg_uid = str(msg_id)
+                            
+                            _logger.info("Mensaje enviado exitosamente. ID: %s", msg_uid)
+                            whatsapp_message.write({
+                                'state': 'sent',
+                                'msg_uid': msg_uid
+                            })
+                            self._cr.commit()
+                        else:
+                            _logger.warning("Respuesta exitosa pero sin jobId ni id: %s", response_json)
+                            whatsapp_message.write({
+                                'state': 'outgoing'
+                            })
+                            self._cr.commit()
+                    except ValueError:
+                        _logger.error("La respuesta no es JSON válido: %s", response.text)
+                        whatsapp_message.write({
+                            'state': 'error'
+                        })
+                        self._cr.commit()
+                else:
+                    _logger.error("Error en la petición. Código: %s, Respuesta: %s", response.status_code, response.text)
                     whatsapp_message.write({
-                        'state': 'sent',
-                        'msg_uid': response_json['_data']['id']['_serialized']
+                        'state': 'error'
                     })
                     self._cr.commit()
-                else:
-                    _logger.info("La respuesta no contiene 'data->id'.")
-            else:
-                _logger.info(f"Error en la petición. Código de estado: {response.status_code}")
+            except requests.exceptions.RequestException as e:
+                _logger.error("Error de conexión al enviar mensaje: %s", str(e))
+                whatsapp_message.write({
+                    'state': 'error'
+                })
+                self._cr.commit()
 
             time.sleep(random.randint(3, 7))

+ 3 - 3
views/whatsapp_account_views.xml

@@ -11,9 +11,9 @@
                     WhatsApp Web
                 </div>
                 <group>
-                    <field name="whatsapp_web_url" placeholder="e.g. https://web.whatsapp.com/"/>
-                    <field name="whatsapp_web_login" placeholder="Ingrese su Login"/>
-                    <field name="whatsapp_web_api_key" placeholder="Ingrese su API Key" password="True"/>
+                    <field name="whatsapp_web_url" placeholder="https://wsrvb.crm.m22.mx" help="Base URL de la API Gateway"/>
+                    <field name="whatsapp_web_login" placeholder="mcteam" help="Nombre de sesión (session_name)"/>
+                    <field name="whatsapp_web_api_key" placeholder="API Key" password="True" help="API Key para autenticación en la API Gateway"/>
                 </group>
             </sheet>
         </field>