erp-core/docs/01-analisis-referencias/odoo/odoo-mail-analysis.md

6.2 KiB

Análisis del Módulo Mail de Odoo

Módulo: mail Prioridad: P0 Mapeo MGN: MGN-014 (Mensajería y Notificaciones)

Descripción

Módulo transversal que proporciona:

  • Sistema de mensajería interna
  • Tracking de cambios (auditoría)
  • Notificaciones
  • Followers (seguidores de registros)
  • Actividades programadas
  • Chatter UI

Modelos Principales

mail.thread (Mixin)

Casi todos los modelos heredan de mail.thread:

class SaleOrder(models.Model):
    _name = 'sale.order'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    state = fields.Selection(tracking=True)  # Cambios tracked
    amount_total = fields.Monetary(tracking=True)

mail.message (Mensajes)

  • Mensajes en timeline (chatter)
  • Tipos: notification, comment, email
  • Adjuntos
  • Followers notificados

mail.followers (Seguidores)

  • Usuarios que siguen un registro
  • Notificaciones automáticas
  • Tipos de eventos suscritos

mail.activity (Actividades)

  • Tareas pendientes vinculadas a registros
  • Recordatorios
  • Asignación a usuarios

Patrones Destacables

1. Tracking Automático de Cambios

# Con tracking=True
state = fields.Selection([...], tracking=True)

# Odoo automáticamente crea mensaje:
# "Estado cambió de 'Draft' a 'Confirmed' por John Doe"

2. Sistema de Notificaciones

# Notificar a followers
self.message_post(
    body="Orden de venta confirmada",
    subject="Orden #SO001",
    message_type='notification'
)
# Todos los followers reciben notificación

3. Followers

# Agregar follower
self.message_subscribe(partner_ids=[partner.id])

# Los followers reciben:
# - Mensajes nuevos
# - Cambios en campos tracked
# - Notificaciones del registro

4. Actividades

# Crear actividad (recordatorio)
self.activity_schedule(
    'mail.mail_activity_data_call',
    date_deadline=fields.Date.today() + timedelta(days=7),
    summary='Llamar al cliente',
    user_id=salesperson.id
)

Mapeo a MGN-014

Requerimientos Funcionales

RF-NOT-001: Sistema de notificaciones

  • Notificaciones en tiempo real (WebSocket)
  • Notificaciones por email
  • Centro de notificaciones en UI

RF-NOT-002: Mensajería interna

  • Chat entre usuarios
  • Mensajes vinculados a registros
  • Adjuntos

RF-NOT-003: Tracking de cambios

  • Auditoría automática de modificaciones
  • Timeline de actividad
  • Quién cambió qué y cuándo

RF-NOT-004: Actividades y tareas

  • Recordatorios programados
  • Asignación a usuarios
  • Follow-up automático

Implementación Recomendada MGN-014

Schema: notifications

CREATE TABLE notifications.messages (
  id SERIAL PRIMARY KEY,
  tenant_id INT NOT NULL,
  model VARCHAR(100) NOT NULL,  -- 'sales.orders', 'purchase.orders'
  record_id INT NOT NULL,
  message_type VARCHAR(50),  -- 'comment', 'notification', 'email'
  subject VARCHAR(200),
  body TEXT,
  author_id INT REFERENCES auth.users(id),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE notifications.followers (
  id SERIAL PRIMARY KEY,
  tenant_id INT NOT NULL,
  model VARCHAR(100) NOT NULL,
  record_id INT NOT NULL,
  user_id INT REFERENCES auth.users(id),
  subscribed_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE (model, record_id, user_id)
);

CREATE TABLE notifications.activities (
  id SERIAL PRIMARY KEY,
  tenant_id INT NOT NULL,
  model VARCHAR(100) NOT NULL,
  record_id INT NOT NULL,
  activity_type VARCHAR(50),  -- 'call', 'email', 'meeting', 'todo'
  summary VARCHAR(200),
  description TEXT,
  assigned_to INT REFERENCES auth.users(id),
  due_date DATE,
  completed BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE notifications.tracking (
  id SERIAL PRIMARY KEY,
  tenant_id INT NOT NULL,
  model VARCHAR(100) NOT NULL,
  record_id INT NOT NULL,
  field_name VARCHAR(100),
  old_value TEXT,
  new_value TEXT,
  changed_by INT REFERENCES auth.users(id),
  changed_at TIMESTAMPTZ DEFAULT NOW()
);

Backend: Tracking Middleware

// Middleware para tracking automático
export function trackingMiddleware(Model: any) {
  const originalUpdate = Model.update;

  Model.update = async function(id: number, data: any, userId: number) {
    // Leer valores actuales
    const oldRecord = await Model.findById(id);

    // Actualizar
    const updatedRecord = await originalUpdate.call(this, id, data);

    // Identificar cambios
    const changes = detectChanges(oldRecord, updatedRecord, Model.trackedFields);

    // Crear registros de tracking
    for (const change of changes) {
      await createTrackingRecord({
        model: Model.tableName,
        record_id: id,
        field_name: change.field,
        old_value: change.oldValue,
        new_value: change.newValue,
        changed_by: userId
      });

      // Notificar a followers
      await notifyFollowers(Model.tableName, id, {
        type: 'field_change',
        field: change.field,
        old: change.oldValue,
        new: change.newValue
      });
    }

    return updatedRecord;
  };
}

Frontend: Notificaciones en Tiempo Real

// WebSocket para notificaciones
const socket = io(WS_URL);

socket.on('notification', (notification) => {
  // Mostrar toast
  toast.info(notification.message);

  // Actualizar contador
  notificationStore.incrementUnread();

  // Reproducir sonido
  playNotificationSound();
});

Patrón de Chatter UI

Odoo tiene un "Chatter" en cada formulario:

  • Timeline de mensajes
  • Actividades pendientes
  • Formulario para escribir mensajes
  • Lista de followers

MGN-014 debe implementar componente similar:

<RecordChatter
  model="sales.orders"
  recordId={order.id}
  userId={currentUser.id}
/>

WebSocket vs Polling

Odoo usa: Polling (cada 30 segundos consulta nuevas notificaciones)

MGN-014 debe usar: WebSocket (Socket.IO o native WebSockets)

  • Notificaciones en tiempo real
  • Menor carga en servidor
  • Mejor UX

Aplicabilidad

- ESENCIAL

El patrón de mail.thread es uno de los más valiosos de Odoo. Permite:

  • Auditoría completa sin código adicional
  • Colaboración en registros
  • Sistema de notificaciones unificado

Recomendación: Implementar tracking automático desde el inicio


Fecha: 2025-11-23 Estado: Análisis completo