Oleada UX 7: Chat (presencia, busqueda en historial) y WACRM (metricas para gerencia, notas internas y etiquetas que sobreviven al sync) + fixes de concurrencia
This commit is contained in:
@@ -2,3 +2,4 @@ from . import main
|
||||
from . import wacrm_sync
|
||||
from . import frontend_user
|
||||
from . import config_audit
|
||||
from . import wacrm_notes
|
||||
|
||||
@@ -27,6 +27,10 @@ class SkeenFrontendUser(models.Model):
|
||||
active = fields.Boolean(string='Activo', default=True)
|
||||
must_change_password = fields.Boolean(string='Debe cambiar contraseña', default=False)
|
||||
last_login = fields.Datetime(string='Último acceso', readonly=True)
|
||||
# Presencia: se actualiza con cada llamada autenticada del frontend
|
||||
# (heartbeat explícito cada ~30 s y en cada endpoint de chat).
|
||||
# "En línea" = actividad en los últimos 2 minutos.
|
||||
last_seen = fields.Datetime(string='Última actividad', readonly=True, index=True)
|
||||
notes = fields.Text(string='Notas')
|
||||
allowed_menus = fields.Text(string='Menús Permitidos',
|
||||
help='JSON array de hrefs visibles; vacío = defaults por rol')
|
||||
|
||||
60
odoo-addons/skeen_whatsapp/models/wacrm_notes.py
Normal file
60
odoo-addons/skeen_whatsapp/models/wacrm_notes.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class SkeenWacrmNote(models.Model):
|
||||
"""Nota interna de una conversación de WhatsApp.
|
||||
|
||||
Se liga por `external_id` de la conversación (NO por many2one al caché
|
||||
local) a propósito: el sync borra y recrea el caché de conversaciones y
|
||||
mensajes, y las notas deben sobrevivir. Nunca se envía al paciente.
|
||||
"""
|
||||
_name = 'skeen.wacrm.note'
|
||||
_description = 'Nota interna de conversación WACRM'
|
||||
_order = 'create_date desc, id desc'
|
||||
|
||||
conversation_external_id = fields.Char(string='ID conversación WACRM',
|
||||
required=True, index=True)
|
||||
contact_name = fields.Char(string='Contacto', help='Sólo para mostrar en la lista')
|
||||
body = fields.Text(string='Nota', required=True)
|
||||
author_name = fields.Char(string='Autor')
|
||||
author_login = fields.Char(string='Autor (usuario)')
|
||||
resolved = fields.Boolean(string='Atendida', default=False)
|
||||
resolved_at = fields.Datetime(string='Fecha de atención')
|
||||
resolved_by = fields.Char(string='Atendida por')
|
||||
# create_date (heredado) = fecha de la nota
|
||||
|
||||
|
||||
class SkeenWacrmTag(models.Model):
|
||||
"""Catálogo de etiquetas de conversación (urgente, cotización, etc.)."""
|
||||
_name = 'skeen.wacrm.tag'
|
||||
_description = 'Etiqueta de conversación WACRM'
|
||||
_order = 'sequence, name'
|
||||
|
||||
name = fields.Char(string='Nombre', required=True)
|
||||
color = fields.Char(string='Color', default='#605ca8')
|
||||
sequence = fields.Integer(string='Orden', default=10)
|
||||
active = fields.Boolean(string='Activa', default=True)
|
||||
|
||||
_sql_constraints = [
|
||||
('unique_name', 'unique(name)', 'Ya existe una etiqueta con ese nombre.'),
|
||||
]
|
||||
|
||||
|
||||
class SkeenWacrmConversationTag(models.Model):
|
||||
"""Asignación etiqueta ↔ conversación, por external_id (sobrevive al sync)."""
|
||||
_name = 'skeen.wacrm.conversation.tag'
|
||||
_description = 'Etiqueta asignada a una conversación WACRM'
|
||||
_order = 'id'
|
||||
|
||||
conversation_external_id = fields.Char(string='ID conversación WACRM',
|
||||
required=True, index=True)
|
||||
tag_id = fields.Many2one('skeen.wacrm.tag', string='Etiqueta',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
assigned_by = fields.Char(string='Asignada por')
|
||||
|
||||
_sql_constraints = [
|
||||
('unique_conv_tag', 'unique(conversation_external_id, tag_id)',
|
||||
'Esa etiqueta ya está asignada a la conversación.'),
|
||||
]
|
||||
Reference in New Issue
Block a user