root před 10 měsíci
rodič
revize
af0a73844a

+ 1 - 0
__init__.py

@@ -0,0 +1 @@
+from . import models

+ 18 - 0
__manifest__.py

@@ -0,0 +1,18 @@
+{
+    'name': 'WhatsApp Web',
+    'version': '1.0',
+    'category': 'Marketing/Marketing',
+    'summary': 'Integra WhatsApp con la automatización de marketing',
+    'description': """
+        Este módulo integra WhatsApp con la automatización de marketing de Odoo,
+        permitiendo enviar mensajes de WhatsApp a través de una URL personalizada.
+    """,
+    'author': 'Tu Nombre',
+    'website': 'https://www.tuempresa.com',
+    'depends': ['whatsapp'],
+    'data': [
+        'views/whatsapp_account_views.xml'
+    ],
+    'installable': True,
+    'auto_install': False,
+}

binární
__pycache__/__init__.cpython-310.pyc


+ 3 - 0
models/__init__.py

@@ -0,0 +1,3 @@
+from . import whatsapp_message
+from . import whatsapp_patch
+from . import whatsapp_account

binární
models/__pycache__/__init__.cpython-310.pyc


binární
models/__pycache__/marketing_activity.cpython-310.pyc


binární
models/__pycache__/res_config_settings.cpython-310.pyc


binární
models/__pycache__/whatsapp_message.cpython-310.pyc


+ 18 - 0
models/res_config_settings.py

@@ -0,0 +1,18 @@
+from odoo import models, fields
+
+class ResConfigSettings(models.TransientModel):
+    _inherit = 'res.config.settings'
+
+    module_whatsapp_web = fields.Boolean("Activar WhatsApp Marketing")
+    whatsapp_endpoint = fields.Char(string="URL de envío de WhatsApp", config_parameter="whatsapp_web.whatsapp_endpoint")
+
+    def set_values(self):
+        super(ResConfigSettings, self).set_values()
+        self.env['ir.config_parameter'].sudo().set_param('whatsapp_web.whatsapp_endpoint', self.whatsapp_endpoint)
+
+    def get_values(self):
+        res = super(ResConfigSettings, self).get_values()
+        res.update(
+            whatsapp_endpoint=self.env['ir.config_parameter'].sudo().get_param('whatsapp_web.whatsapp_endpoint')
+        )
+        return res

+ 10 - 0
models/whatsapp_account.py

@@ -0,0 +1,10 @@
+import logging
+
+from odoo import fields, models
+
+_logger = logging.getLogger(__name__)
+
+class WhatsAppAccount(models.Model):
+    _inherit = ['whatsapp.account']
+
+    whatsapp_web_url = fields.Char(string="WhatsApp Web URL", readonly=False, copy=False)

+ 158 - 0
models/whatsapp_message.py

@@ -0,0 +1,158 @@
+from odoo import models, fields, api
+from odoo.tools import groupby
+import logging
+import markupsafe
+import requests
+import json
+import time
+import random
+import re
+import html
+import base64
+
+_logger = logging.getLogger(__name__)
+
+class WhatsAppMessage(models.Model):
+    _inherit = 'whatsapp.message'
+
+    
+    def _send_message(self, with_commit=False):
+
+        url = ''
+
+        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)
+
+        group = ''
+        
+        if not url:
+            super()._send_message(with_commit)
+            
+        for whatsapp_message in self:
+            #verificacion envio a grupo
+            #plantilla dada de alta en x_plantillas_whatsapp 
+            marketing_traces = self.env['marketing.trace'].sudo().search([('whatsapp_message_id', '=', whatsapp_message.id)])
+            for marketing_trace in marketing_traces:
+                if marketing_trace.activity_id.x_studio_grupo_whatsapp:
+                    group = marketing_trace.activity_id.x_studio_grupo_whatsapp.x_studio_destinatario
+
+            if not group and False: 
+                notificaciones = self.env['x_notificaciones_whats'].sudo().search([('x_studio_plantilla_de_whatsapp', '=', whatsapp_message.wa_template_id.id)])
+                if notificaciones:
+                    _logger.info('template encontrado')
+                    
+                    phone_field = whatsapp_message.wa_template_id.phone_field
+                    _logger.info(phone_field)
+                    phone_field = (phone_field.rpartition('.')[0] + '.id') if '.' in phone_field else phone_field
+                    _logger.info(phone_field)
+                    partners_ids = record._find_value_from_field_path(phone_field)
+                    if partners_ids:
+                        partners_ids = list(map(int, partners_ids.split()))
+                        for notificacion in notificaciones:
+                            if notificacion.x_studio_partner_unico.id in partners_ids:
+                                _logger.info('destinatario:' + notificacion.x_studio_destinatario)
+                                group = notificacion.x_studio_destinatario
+                                break
+                    if not group: 
+                        for notificacion in notificaciones:
+                            if not notificacion.x_studio_partner_unico:
+                                group = notificacion.x_studio_destinatario
+                                break
+            
+            attachment = False
+
+            if whatsapp_message.wa_template_id:
+                record = self.env[whatsapp_message.wa_template_id.model].browse(whatsapp_message.mail_message_id.res_id)
+                #codigo con base a whatsapp.message y whatsapp.template para generacion de adjuntos
+                RecordModel = self.env[whatsapp_message.mail_message_id.model].with_user(whatsapp_message.create_uid)
+                from_record = RecordModel.browse(whatsapp_message.mail_message_id.res_id)
+
+                # if retrying message then we need to unlink previous attachment
+                # in case of header with report in order to generate it again
+                if whatsapp_message.wa_template_id.report_id and whatsapp_message.wa_template_id.header_type == 'document' and whatsapp_message.mail_message_id.attachment_ids:
+                    whatsapp_message.mail_message_id.attachment_ids.unlink()
+
+                if not attachment and whatsapp_message.wa_template_id.report_id:
+                    attachment = whatsapp_message.wa_template_id._generate_attachment_from_report(record)
+                if not attachment and whatsapp_message.wa_template_id.header_attachment_ids:
+                    attachment = whatsapp_message.wa_template_id.header_attachment_ids[0]
+                
+                if attachment and attachment not in whatsapp_message.mail_message_id.attachment_ids:
+                    whatsapp_message.mail_message_id.attachment_ids = [(4, attachment.id)]
+             # no template
+            elif whatsapp_message.mail_message_id.attachment_ids:
+                attachment = whatsapp_message.mail_message_id.attachment_ids[0]
+
+            #codigo para limpiar body y numero
+            body = whatsapp_message.body
+            if isinstance(body, markupsafe.Markup):
+                text = html.unescape(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)
+                
+                # 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)
+                
+                # Limpiamos espacios en blanco al inicio y final
+                body = text.strip()
+
+            number = whatsapp_message.mobile_number
+            number = number.replace(' ', '').replace('+','')
+
+            if number.startswith("52") and len(number) == 12:
+                number = "521" + number[2:]
+
+            # ENVIO DE MENSAJE
+            # Headers de la petición, si es necesario
+            headers = {
+                "Content-Type": "application/json"
+            }
+
+            number = group if group else number + '@c.us'
+            
+            #$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]);
+            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
+            if attachment:
+                payload = {
+                    "method": "sendMessage",  
+                    "args": [number, {'type': 'MessageMedia', 'args': [attachment.mimetype, base64.b64encode(attachment.raw).decode('utf-8'), attachment.name, attachment.file_size]}, {'caption': body}]
+                }
+            else: 
+                payload = {
+                    "method": "sendMessage",  
+                    "args": [number, body, {}]
+                }
+
+            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:
+                response_json = 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']}")
+                    whatsapp_message.write({
+                        'state': 'sent',
+                        'msg_uid': response_json['_data']['id']['_serialized']
+                    })
+                    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}")
+
+            time.sleep(random.randint(3, 7))

+ 23 - 0
models/whatsapp_patch.py

@@ -0,0 +1,23 @@
+import logging
+import base64
+from odoo.addons.whatsapp.tools.whatsapp_api import WhatsAppApi
+
+_logger = logging.getLogger(__name__)
+
+# Guarda una referencia al método original
+original_get_whatsapp_document = WhatsAppApi._get_whatsapp_document
+
+def custom_get_whatsapp_document(self, document_id):
+    _logger.info("Ejecutando versión modificada de _get_whatsapp_document")
+
+    if self.wa_account_id.whatsapp_web_url: 
+        _logger.info("Ejecutando versión modificada de _get_whatsapp_document con whatsapp web")
+        result = base64.b64decode(document_id)
+    else:
+        result = original_get_whatsapp_document(self, document_id)
+
+    # Aquí puedes modificar 'result' si es necesario antes de devolverlo
+    return result
+
+# Sobrescribir el método en tiempo de ejecución
+WhatsAppApi._get_whatsapp_document = custom_get_whatsapp_document

+ 2 - 0
security/ir.model.access.csv

@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_whatsapp_web_config,access_whatsapp_web_config,model_res_config_settings,base.group_system,1,1,1,1

+ 22 - 0
views/res_config_settings_views.xml

@@ -0,0 +1,22 @@
+<odoo>
+    <record id="view_res_config_settings_form_inherit_whatsapp" model="ir.ui.view">
+        <field name="name">res.config.settings.whatsapp.marketing.form</field>
+        <field name="model">res.config.settings</field>
+        <field name="inherit_id" ref="base.res_config_settings_view_form"/>
+        <field name="arch" type="xml">
+            <xpath expr="//form" position="inside">
+                <div class="mt16">
+                    <h2>WhatsApp Marketing</h2>
+                    <div class="row">
+                        <div class="col-12 col-lg-6">
+                            <field name="module_whatsapp_web"/>
+                        </div>
+                        <div class="col-12 col-lg-6">
+                            <field name="whatsapp_endpoint"/>
+                        </div>
+                    </div>
+                </div>
+            </xpath>
+        </field>
+    </record>
+</odoo>

+ 19 - 0
views/whatsapp_account_views.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <record id="whatsapp_account_view_form_custom" model="ir.ui.view">
+        <field name="name">whatsapp.account.view.form.custom</field>
+        <field name="model">whatsapp.account</field>
+        <field name="inherit_id" ref="whatsapp.whatsapp_account_view_form"/>
+        <field name="arch" type="xml">
+            <!-- Agregamos una nueva sección al final del <sheet> -->
+            <sheet position="inside">
+                <div class="o_horizontal_separator mt-4 mb-3 text-uppercase fw-bolder small">
+                    WhatsApp Web
+                </div>
+                <group>
+                    <field name="whatsapp_web_url" placeholder="e.g. https://web.whatsapp.com/"/>
+                </group>
+            </sheet>
+        </field>
+    </record>
+</odoo>