Ir al contenido

RGPD en módulos Odoo: datos sensibles y portal

Separar el cliente del perfil sensible, acceso restringido y trazabilidad
18 de julio de 2026 por
RGPD en módulos Odoo: datos sensibles y portal
ATEMI, Aitor Atencia

Odoo · RGPD · Portal

Muchos servicios distinguen entre quien contrata y paga (el cliente, un res.partner facturable) y la persona sobre la que se guardan datos sensibles: un paciente, un empleado, un beneficiario. Mezclar las dos cosas en el mismo registro 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 el partner comercial del perfil sensible reduce la superficie de exposición.

Modelo

Cliente frente a perfil sensible

class ServiceProfile(models.Model):
    _name = 'service.profile'
    _description = 'Service Profile'

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

class ServiceRequest(models.Model):
    _name = 'service.request'
    _inherit = ['mail.thread']

    partner_id = fields.Many2one('res.partner', string='Customer')
    profile_id = fields.Many2one(
        'service.profile',
        string='Profile',
        required=True,
    )

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

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

Permisos

Tres roles, tres dominios

RolVeRecord rule típica
Cliente (portal)Sus solicitudes y documentos entregados('partner_id', '=', user.partner_id.id)
TécnicoSolicitudes asignadas('technician_id', '=', user.id)
AdminTodo (auditoría)Sin regla restrictiva + grupo system
<record id="rule_profile_technician" model="ir.rule">
    <field name="name">Profile: assigned technician only</field>
    <field name="model_id" ref="model_service_profile"/>
    <field name="domain_force">[
        ('request_ids.technician_id', '=', user.id)
    ]</field>
    <field name="groups" eval="[(4, ref('group_service_technician'))]"/>
</record>

Campos sensibles

groups= y chatter selectivo

private_notes = fields.Text(
    string='Private Notes',
    groups='my_module.group_service_technician',
)
signed_document = fields.Binary(
    groups='my_module.group_service_user,'
           'my_module.group_service_technician',
)

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/requests', type='http', auth='user', website=True)
def portal_requests(self, **kw):
    records = request.env['service.request'].search([
        ('partner_id', '=', request.env.user.partner_id.id),
    ])
    return request.render('my_module.portal_request_list', {'records': records})

@http.route('/my/requests/document/<int:document_id>', auth='user')
def download_document(self, document_id):
    document = request.env['service.document'].browse(document_id)
    if document.request_id.partner_id != request.env.user.partner_id:
        raise NotFound()
    if not document.is_signed:
        raise NotFound()
    return self._stream_pdf(document)
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ó la solicitud y cuándo.
  • Documentos firmados inmutables — bloquear write tras la firma.
  • Derecho de supresión — procedimiento documentado (anonimizar frente a borrar en cascada).
  • Logs — accesos a descargas en ir.logging o en un modelo de auditoría.
def write(self, vals):
    signed = self.filtered('is_signed')
    if signed:
        raise UserError('Signed documents cannot be modified.')
    return super().write(vals)

Resumen

Separa el partner comercial del perfil sensible, define record rules por rol, restringe los campos privados con groups= y valida la propiedad en las rutas del 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