Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions privacy_partner_to_be_forgotten/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=======================================
Privacy Partner's Right to be Forgotten
=======================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0fbaad7301ee791d18e90adb46e9182cd132f4f46fa82f84920c4179c7e0bbef
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdata--protection-lightgray.png?logo=github
:target: https://github.com/OCA/data-protection/tree/19.0/privacy_partner_to_be_forgotten
:alt: OCA/data-protection
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/data-protection-19-0/data-protection-19-0-privacy_partner_to_be_forgotten
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/data-protection&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

The module allows anonymizing contacts that represent natural persons
(i.e., individuals) when they are no longer needed or when a data
erasure request is received.

This module provides a method to anonymize all personally identifiable
information (PII) from a ``res.partner`` record:

- Name (e.g., replaced with initials or a generic label) for individual
contacts
- Email address
- Phone numbers
- Street and address fields
- Tax ID
- Citizen Identification
- Job position and title
- Internal Notes
- Attached images (e.g., avatar)

The anonymization preserves the partner's link to its parent company if
applicable (e.g., for a B2B contact) but ensures that the individual is
no longer identifiable through the remaining data or relationships.

Additionally, the module removes all chatter messages (``mail.message``)
and attachments associated with the partner record, as these may contain
personal information, such as communication history, internal notes, or
file uploads. This ensures complete anonymization and supports full GDPR
compliance.

If the partner is linked to one or more ``res.users`` records (e.g., as
a portal user or employee), the module will anonymize these user
records:

- The user login and email are replaced with anonymized values, and the
user is archived.

A log note is added to the partner record chatter to indicate the
anonymization event, supporting traceability.

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

This module aims to help companies comply with the European Union
General Data Protection Regulation (GDPR) by providing a mechanism to
anonymize personal data in ``res.partner`` records.

Configuration
=============

To permit a user to anonymize partner records:
----------------------------------------------

1. Go to **Settings** → **Users & Companies** → **Users**
2. Select the user you want to authorize
3. In the **Administration** group, enable the checkbox **"Anonymize
Contacts"**

This will allow the user to access and execute the anonymization
functionality provided by the module.

Usage
=====

To anonymize a partner record:
------------------------------

NOTE: **Make sure the user has permission** to anonymize partner
records. Please check the Configuration file for details on how to grant
permission.

1. Go to the **Contacts App** in Odoo.
2. Select the partner record you want to anonymize.
3. Go to **Actions** → **Anonymize (GDPR)**.
4. A confirmation wizard will appear. Press the **"Confirm"** button to
proceed.

Once you confirm, Odoo will anonymize the partner's record and all
related child records, including:

- Chatter messages and attachments
- Linked ``res.users`` (user) records, if applicable

**Important:**

- The anonymization operation **cannot be undone**.
- Please be aware that once the data is anonymized, it cannot be
restored, so proceed carefully.
- You carry full responsibility for using the module's features, in line
with GDPR compliance.

Changelog
=========



Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/data-protection/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/data-protection/issues/new?body=module:%20privacy_partner_to_be_forgotten%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Cetmix

Contributors
------------

- `Cetmix <https://cetmix.com/>`__:

- Mikhail Lapin
- Anatol Mikheev

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/data-protection <https://github.com/OCA/data-protection/tree/19.0/privacy_partner_to_be_forgotten>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
5 changes: 5 additions & 0 deletions privacy_partner_to_be_forgotten/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (C) 2025 Cetmix OÜ
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from . import models
from . import wizards
21 changes: 21 additions & 0 deletions privacy_partner_to_be_forgotten/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (C) 2025 Cetmix OÜ
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

{
"name": "Privacy Partner's Right to be Forgotten",
"version": "19.0.1.0.0",
"development_status": "Beta",
"category": "Data Protection",
"summary": "Anonymize partner data for GDPR compliance",
"author": "Cetmix, Odoo Community Association (OCA)",
"license": "LGPL-3",
"website": "https://github.com/OCA/data-protection",
"depends": ["contacts"],
"data": [
"security/security.xml",
"security/ir.model.access.csv",
"views/res_partner_views.xml",
"wizards/partner_anonymize_wizard_views.xml",
],
"demo": ["demo/demo_partner_anonymize_data.xml"],
}
134 changes: 134 additions & 0 deletions privacy_partner_to_be_forgotten/demo/demo_partner_anonymize_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<!-- Test Partners -->
<record id="partner_company_sodasopa" model="res.partner">
<field name="name">Sodasopa</field>
<field name="is_company" eval="True" />
<field name="phone">+1 123-456-7890</field>
<field name="email">info@sodasopa.com</field>
<field name="street">123 Main St</field>
<field name="city">South Park</field>
<field name="zip">80435</field>
<field name="country_id" ref="base.us" />
<field name="website">www.sodasopa.com</field>
<field name="vat">US123456789</field>
</record>

<record id="partner_eric_cartman" model="res.partner">
<field name="name">Eric Cartman</field>
<field name="parent_id" ref="partner_company_sodasopa" />
<field name="phone">+1 123-456-7891</field>
<field name="email">eric@sodasopa.com</field>
<field name="street">124 Main St</field>
<field name="city">South Park</field>
<field name="zip">80435</field>
<field name="country_id" ref="base.us" />
<field name="function">Manager</field>
</record>

<record id="partner_butters_stotch" model="res.partner">
<field name="name">Butters Stotch</field>
<field name="parent_id" ref="partner_company_sodasopa" />
<field name="phone">+1 123-456-7893</field>
<field name="email">butters@sodasopa.com</field>
<field name="street">125 Main St</field>
<field name="city">South Park</field>
<field name="zip">80435</field>
<field name="country_id" ref="base.us" />
<field name="function">Assistant</field>
</record>

<record id="partner_kenny_mccormick" model="res.partner">
<field name="name">Kenny McCormick</field>
<field name="parent_id" ref="partner_eric_cartman" />
<field name="phone">+1 123-456-7895</field>
<field name="email">kenny@sodasopa.com</field>
<field name="street">126 Main St</field>
<field name="city">South Park</field>
<field name="zip">80435</field>
<field name="country_id" ref="base.us" />
<field name="function">Intern</field>
</record>

<record id="partner_stanley_marsh" model="res.partner">
<field name="name">Stanley Marsh</field>
<field name="phone">+1 123-456-7897</field>
<field name="email">stan@sp.com</field>
<field name="street">127 Main St</field>
<field name="city">South Park</field>
<field name="zip">80435</field>
<field name="country_id" ref="base.us" />
<field name="function">Student</field>
</record>

<!-- Test Users -->
<record
id="user_company_sodasopa"
model="res.users"
context="{'no_reset_password': True}"
>
<field name="partner_id" ref="partner_company_sodasopa" />
<field name="login">sodasopa</field>
<field name="password">sodasopa</field>
<field name="name">Sodasopa</field>
<field name="email">info@sodasopa.com</field>
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]" />
<field name="action_id" ref="mail.action_discuss" />
</record>

<record
id="user_eric_cartman"
model="res.users"
context="{'no_reset_password': True}"
>
<field name="partner_id" ref="partner_eric_cartman" />
<field name="login">eric</field>
<field name="password">eric</field>
<field name="name">Eric Cartman</field>
<field name="email">eric@sodasopa.com</field>
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]" />
<field name="action_id" ref="mail.action_discuss" />
</record>

<record
id="user_butters_stotch"
model="res.users"
context="{'no_reset_password': True}"
>
<field name="partner_id" ref="partner_butters_stotch" />
<field name="login">butters</field>
<field name="password">butters</field>
<field name="name">Butters Stotch</field>
<field name="email">butters@sodasopa.com</field>
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]" />
<field name="action_id" ref="mail.action_discuss" />
</record>

<record
id="user_kenny_mccormick"
model="res.users"
context="{'no_reset_password': True}"
>
<field name="partner_id" ref="partner_kenny_mccormick" />
<field name="login">kenny</field>
<field name="password">kenny</field>
<field name="name">Kenny McCormick</field>
<field name="email">kenny@sodasopa.com</field>
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]" />
<field name="action_id" ref="mail.action_discuss" />
</record>

<record
id="user_stanley_marsh"
model="res.users"
context="{'no_reset_password': True}"
>
<field name="partner_id" ref="partner_stanley_marsh" />
<field name="login">stan</field>
<field name="password">stan</field>
<field name="name">Stanley Marsh</field>
<field name="email">stan@sp.com</field>
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]" />
<field name="action_id" ref="mail.action_discuss" />
</record>
</odoo>
Loading
Loading