Ir al contenido

RGPD en módulos Odoo: datos de menores y portal

Separación de partners, acceso restringido y trazabilidad
22 de junio de 2026 por
RGPD en módulos Odoo: datos de menores y portal
Atemi, Aitor Atencia

Odoo · RGPD · Portal

En proyectos con datos de menores o salud, mezclar titular del servicio (res.partner facturable) con el perfil evaluado es un error de diseño y de cumplimiento. Odoo no trae RGPD «de serie»: hay que modelarlo con separación de entidades, permisos granulares y trazabilidad.

Logo Odoo Privacidad
Separar partner comercial de perfil sensible reduce superficie de exposición.

Modelo

Partner vs sujeto evaluado

class DiagnosticTestSubject(models.Model):
    _name = 'diagnostic.test.subject'
    _description = 'Diagnostic Test Subject'

    name = fields.Char(required=True)
    birth_date = fields.Date()
    partner_id = fields.Many2one('res.partner')  # Tutor / pagador

class DiagnosticTest(models.Model):
    _name = 'diagnostic.test'
    _inherit = ['mail.thread']

    partner_id = fields.Many2one('res.partner', string='Customer')
    subject_id = fields.Many2one(
        'diagnostic.test.subject',
        string='Candidate',
        required=True,
    )

El cliente portal ve sus pedidos vía partner_id; los datos del menor viven en un modelo con ACL más restrictivos y campos con groups=.

Minimización de datos: no copies nombre/fecha de nacimiento del menor a res.partner «por comodidad». Duplicar es duplicar riesgo.

Permisos

Tres roles, tres dominios

RolVeRecord rule típica
Cliente (portal)Sus diagnósticos e informes entregados('partner_id', '=', user.partner_id.id)
ProfesionalDiagnósticos asignados('professional_id', '=', user.id)
AdminTodo (auditoría)Sin regla restrictiva + grupo system
<record id="rule_subject_professional" model="ir.rule">
    <field name="name">Subject: assigned professional only</field>
    <field name="model_id" ref="model_diagnostic_test_subject"/>
    <field name="domain_force">[
        ('test_ids.professional_id', '=', user.id)
    ]</field>
    <field name="groups" eval="[(4, ref('group_diagnostic_professional'))]"/>
</record>

Campos sensibles

groups= y chatter selectivo

clinical_notes = fields.Text(
    string='Clinical Notes',
    groups='diagnostic_tests.group_diagnostic_professional',
)
report_signed = fields.Binary(
    groups='diagnostic_tests.group_diagnostic_user,'
           'diagnostic_tests.group_diagnostic_professional',
)

Los campos con groups= desaparecen de vistas y RPC para quien no pertenece al grupo. Complementa — no sustituye — record rules.

Portal

Controladores portal sin fugas

@http.route('/my/diagnostics', type='http', auth='user', website=True)
def portal_diagnostics(self, **kw):
    tests = request.env['diagnostic.test'].search([
        ('partner_id', '=', request.env.user.partner_id.id),
    ])
    return request.render('diagnostic_tests.portal_list', {'tests': tests})

@http.route('/my/diagnostic/report/<int:report_id>', auth='user')
def download_report(self, report_id):
    report = request.env['diagnostic.test.report'].browse(report_id)
    if report.diagnostic_id.partner_id != request.env.user.partner_id:
        raise NotFound()
    if not report.is_signed:
        raise NotFound()
    return self._stream_pdf(report)
Portal Odoo
En portal, 404 homogéneo mejor que «no tienes permiso» (evita enumerar IDs).

Trazabilidad

Tracking, retención e inmutabilidad

  • Estados con tracking=True — quién movió el diagnóstico y cuándo.
  • Informes firmados inmutables — bloquear write tras firma digital.
  • Derecho de supresión — procedimiento documentado (anonimizar vs borrar cascada).
  • Logs — accesos a descarga de informes en ir.logging o modelo de auditoría.
def write(self, vals):
    signed = self.filtered('is_signed')
    if signed:
        raise UserError('Signed reports cannot be modified.')
    return super().write(vals)

Resumen

Separa partner comercial y perfil sensible, define record rules por rol, restringe campos clínicos con groups= y valida ownership en rutas portal. RGPD en Odoo es arquitectura + permisos + procesos, no un checkbox legal.

en Odoo
Seguridad en controladores web y rutas HTTP en Odoo
auth='user', validación de entrada y whitelist de campos en write