bloque 4: campanas por segmentos con medicion (modulo skeen_campanas: segmentos reutilizables con conteo verificado, campanas por WhatsApp y correo con programacion, prueba previa, limite por minuto, pausa por errores, consentimiento por canal y atribucion de citas) + encuesta al salir con NPS (campo propio, envio automatico y recordatorio, reporte con tendencia y desglose); apagado por defecto

This commit is contained in:
2026-10-12 02:34:34 +00:00
parent 705b5a2842
commit a6d6df4ebd
37 changed files with 4619 additions and 44 deletions

View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
"""Consentimiento de marketing del paciente, por canal.
Las campañas (marketing) NUNCA escriben a quien no autorizó recibirlas. Los
avisos transaccionales (recordatorio de cita, confirmación, encuesta de salida)
NO dependen de esto: son parte del servicio que el paciente ya contrató.
El consentimiento es explícito y nace APAGADO: la clínica lo registra cuando el
paciente lo autoriza (por WhatsApp, en recepción, etc.). `consentimiento_marketing`
es el interruptor general; `consentimiento_whatsapp` / `consentimiento_email`
autorizan canal por canal.
"""
from odoo import api, fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
consentimiento_marketing = fields.Boolean(
string='Acepta marketing', default=False, copy=False,
help='Autorización general para recibir promociones y campañas.')
consentimiento_whatsapp = fields.Boolean(
string='Marketing por WhatsApp', default=False, copy=False)
consentimiento_email = fields.Boolean(
string='Marketing por correo', default=False, copy=False)
consentimiento_at = fields.Datetime(
string='Consentimiento registrado el', copy=False)
consentimiento_origen = fields.Char(
string='Origen del consentimiento', copy=False)
def _marketing_permitido(self, canal):
"""True si el paciente autorizó marketing por `canal` (whatsapp|email).
Exige el interruptor general Y el del canal. Sin autorización explícita
devuelve False: el silencio no es consentimiento.
"""
self.ensure_one()
if not self.consentimiento_marketing:
return False
if canal == 'whatsapp':
return bool(self.consentimiento_whatsapp)
if canal == 'email':
return bool(self.consentimiento_email)
return False
@api.model
def _marcar_consentimiento(self, partner, whatsapp=None, email=None,
general=None, origen=''):
"""Registra el consentimiento de un paciente (update parcial)."""
vals = {}
if general is not None:
vals['consentimiento_marketing'] = bool(general)
if whatsapp is not None:
vals['consentimiento_whatsapp'] = bool(whatsapp)
if email is not None:
vals['consentimiento_email'] = bool(email)
if not vals:
return partner
vals['consentimiento_at'] = fields.Datetime.now()
vals['consentimiento_origen'] = (origen or '')[:120]
partner.write(vals)
return partner