Files
Claude AI 5dd3499097 feat: Major WhatsApp integration update with Odoo and pause/resume
## Frontend
- Add media display (images, audio, video, docs) in Inbox
- Add pause/resume functionality for WhatsApp accounts
- Fix media URLs to use nginx proxy (relative URLs)

## API Gateway
- Add /accounts/:id/pause and /accounts/:id/resume endpoints
- Fix media URL handling for browser access

## WhatsApp Core
- Add pauseSession() - disconnect without logout
- Add resumeSession() - reconnect using saved credentials
- Add media download and storage for incoming messages
- Serve media files via /media/ static route

## Odoo Module (odoo_whatsapp_hub)
- Add Chat Hub interface with DOLLARS theme (dark, 3-column layout)
- Add WhatsApp/DRRR theme switcher for chat view
- Add "ABRIR CHAT" button in conversation form
- Add send_message_from_chat() method
- Add security/ir.model.access.csv
- Fix CSS scoping to avoid breaking Odoo UI
- Update webhook to handle message events properly

## Documentation
- Add docs/CONTEXTO_DESARROLLO.md with complete project context

## Infrastructure
- Add whatsapp_media Docker volume
- Configure nginx proxy for /media/ route
- Update .gitignore to track src/sessions/ source files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 20:48:56 +00:00

125 lines
3.8 KiB
Python

from odoo import models, fields, api
import requests
import logging
_logger = logging.getLogger(__name__)
class WhatsAppMessage(models.Model):
_name = 'whatsapp.message'
_description = 'WhatsApp Message'
_order = 'create_date desc'
external_id = fields.Char(string='ID Externo', index=True)
conversation_id = fields.Many2one(
'whatsapp.conversation',
string='Conversación',
required=True,
ondelete='cascade',
)
direction = fields.Selection([
('inbound', 'Entrante'),
('outbound', 'Saliente'),
], string='Dirección', required=True)
message_type = fields.Selection([
('text', 'Texto'),
('image', 'Imagen'),
('audio', 'Audio'),
('video', 'Video'),
('document', 'Documento'),
('location', 'Ubicación'),
('contact', 'Contacto'),
('sticker', 'Sticker'),
], string='Tipo', default='text')
content = fields.Text(string='Contenido')
media_url = fields.Char(string='URL Media')
status = fields.Selection([
('pending', 'Pendiente'),
('sent', 'Enviado'),
('delivered', 'Entregado'),
('read', 'Leído'),
('failed', 'Fallido'),
], string='Estado', default='pending')
is_read = fields.Boolean(string='Leído', default=False)
sent_by_id = fields.Many2one(
'res.users',
string='Enviado por',
)
error_message = fields.Text(string='Error')
@api.model
def create(self, vals):
message = super().create(vals)
if message.conversation_id:
message.conversation_id.write({
'last_message_at': fields.Datetime.now(),
})
return message
def action_resend(self):
"""Resend failed message"""
self.ensure_one()
if self.status != 'failed':
return
self._send_to_whatsapp_central()
def _send_to_whatsapp_central(self):
"""Send message via WhatsApp Central API"""
self.ensure_one()
account = self.conversation_id.account_id
phone_number = self.conversation_id.phone_number
if not account.external_id:
self.write({
'status': 'failed',
'error_message': 'La cuenta no está vinculada a WhatsApp Central',
})
return
try:
# Use internal endpoint (no auth required)
response = requests.post(
f'{account.api_url}/api/whatsapp/internal/odoo/send',
json={
'phone_number': phone_number,
'message': self.content,
'account_id': account.external_id,
},
timeout=30,
)
if response.status_code == 200:
data = response.json()
self.write({
'external_id': data.get('message_id'),
'status': 'sent',
'error_message': False,
})
else:
self.write({
'status': 'failed',
'error_message': response.text,
})
except Exception as e:
_logger.error(f'Error sending WhatsApp message: {e}')
self.write({
'status': 'failed',
'error_message': str(e),
})
@api.model
def send_message(self, conversation_id, content, message_type='text', media_url=None):
"""Helper to send a new message"""
message = self.create({
'conversation_id': conversation_id,
'direction': 'outbound',
'message_type': message_type,
'content': content,
'media_url': media_url,
'sent_by_id': self.env.user.id,
})
message._send_to_whatsapp_central()
return message