274 lines
6.2 KiB
Markdown
274 lines
6.2 KiB
Markdown
# 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:**
|
|
```python
|
|
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
|
|
|
|
```python
|
|
# 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
|
|
|
|
```python
|
|
# 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
|
|
|
|
```python
|
|
# Agregar follower
|
|
self.message_subscribe(partner_ids=[partner.id])
|
|
|
|
# Los followers reciben:
|
|
# - Mensajes nuevos
|
|
# - Cambios en campos tracked
|
|
# - Notificaciones del registro
|
|
```
|
|
|
|
### 4. Actividades
|
|
|
|
```python
|
|
# 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
|
|
|
|
```sql
|
|
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
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
// 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:**
|
|
```typescript
|
|
<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
|