Vertrauliche Kontakte und Datensichtbarkeit in Odoo
Kurz gesagt
In Odoo 20.0 erlaubt der Eintrag der internen Benutzer im Community-Quellcode das Lesen von res.partner ohne eigene Domäne; die globale Unternehmens-Einschränkung ohne Gruppe begrenzt dieses Lesen dennoch, nimmt aber Kontakte mit verknüpftem internem Benutzer aus. Ganze Kontakte verbergen das Feld Unternehmen (Mehrfirmen; laut Community-Quellcode 20.0 bleiben Kontakte ohne Unternehmen, Kontakte eines übergeordneten Unternehmens und Kontakte interner Benutzer sichtbar) oder eine Einschränkung ohne Gruppe, die für alle Benutzer gilt; feldbezogene Gruppenrechte verbergen einzelne Angaben. In Deutschland und Österreich gilt Art. 32 Abs. 1 DSGVO, in der Schweiz Art. 8 Abs. 1 DSG.
Das Wichtigste
- Im Community-Quellcode 20.0 erlaubt der Eintrag der internen Benutzer das Lesen aller Kontakte ohne eigene Domäne; die globale Unternehmens-Einschränkung ohne Gruppe begrenzt dieses Lesen dennoch.
- Ohne zusätzliche Gruppen ändert ein interner Benutzer nach dem Community-Quellcode 20.0 nur den eigenen Kontakt; die Gruppe Kontakt ▸ Erstellung und Gruppen der Apps Verkauf, Einkauf, Lager und CRM erlauben das Ändern aller Kontakte.
- Gruppenberechtigungen werden laut Entwicklerdokumentation 20.0 mit ODER verknüpft, globale Regeln ohne Gruppe schneiden sich; eine zusätzliche Regel für eine Gruppe verengt den Zugriff deshalb nicht, und nur der Superuser-Modus umgeht Datensatzregeln und Zugriffsrechte.
- Das Feld Unternehmen bindet einen Kontakt an ein Unternehmen und macht ihn damit nur für Benutzer sichtbar, die dieses Unternehmen aktiviert haben (Dokumentation 20.0, Mehrfirmen); laut Community-Quellcode 20.0 lässt die Datensatzregel zusätzlich Kontakte ohne Unternehmen und Kontakte eines übergeordneten Unternehmens durch; Kontakte, die mit einem internen Benutzer verknüpft sind (partner_share = False), bleiben ebenfalls sichtbar.
- Feldbezogene Gruppenrechte entfernen ein Feld laut Entwicklerdokumentation 20.0 aus Ansichten, aus fields_get und aus Lese- und Schreibzugriffen.
- Portalbenutzer lesen laut Community-Quellcode 20.0 (Domäne mit child_of) den eigenen kommerziellen Partner und dessen untergeordnete Kontakte.
Kontakte sind in Odoo die Adressbasis fast jeder App: Verkauf, Einkauf, Rechnungen und E-Mail greifen auf denselben Datensatz zu. Wer einzelne Ansprechpersonen nur einem Teil des Teams zeigen darf, stößt damit auf das Rechte-Modell.
Wie Odoo Sichtbarkeit zusammensetzt
Die Entwicklerdokumentation 20.0 trennt zwei Ebenen: Zugriffsrechte erlauben eine Operation auf einem ganzen Modell, Datensatzregeln prüfen je Datensatz eine Domäne. Zugriffsrechte sind additiv, ein Benutzer darf also, was die Vereinigung seiner Gruppen erlaubt. Globale Regeln ohne Gruppe schneiden sich, Regeln mit Gruppe vereinen sich. Der Community-Quellcode 20.0 schreibt das als Domain.OR(permissions) & Domain.AND(restrictions).
Für Kontakte steht dort der Eintrag res_partner_rule_user: die Gruppe der internen Benutzer, Operation Lesen, ohne eigene Domäne. Diese Erlaubnis bleibt nicht unbedingt, denn die globale Regel res_partner_rule ohne Gruppe schneidet sie; sie nimmt aber Kontakte mit partner_share = False aus, also Kontakte, die mit einem internen Benutzer verknüpft sind. Anlegen und Löschen hängen an der Berechtigung Kontakt ▸ Erstellung (base.group_partner_manager). Das Ändern aller Kontakte erlauben zusätzliche Gruppen der installierten Apps, im Community-Quellcode 20.0 etwa dieselbe Berechtigung Kontakt ▸ Erstellung sowie Gruppen der Apps Verkauf, Einkauf, Lager und CRM. Ohne solche Gruppen ändert ein interner Benutzer nur den eigenen Kontakt. Eine zusätzliche Regel mit Gruppe fügt eine zweite, bedingte Erlaubnis hinzu und verengt den Zugriff deshalb nicht.
Welche Möglichkeiten gibt es?
Die Tabelle stellt die Wege für Odoo 20.0 zusammen.
| Weg | Was er einschränkt | Wen er trifft | Wo Sie ihn setzen | Grenze |
|---|---|---|---|---|
| Unternehmen trennen (Mehrfirmen) | ganze Kontakte, weil das Feld Unternehmen den Kontakt an ein Unternehmen bindet | Benutzer, die dieses Unternehmen nicht aktiviert haben und deren aktivierte Unternehmen ihm nicht untergeordnet sind | Feld Unternehmen im Kontaktformular; Unternehmen des Benutzers im Reiter Zugriffsrechte | Laut Community-Quellcode 20.0 ist das keine Gleichheitsprüfung: Ein Kontakt bleibt sichtbar, wenn sein Unternehmen einem aktivierten Unternehmen übergeordnet ist (parent_of), wenn er keinem Unternehmen zugeordnet ist und wenn er mit einem internen Benutzer verknüpft ist (partner_share = False) |
| Feldbezogenes Gruppenrecht (groups am Feld) | einzelne Felder des Kontakts | Benutzer ohne die eingetragene Gruppe | an der Felddefinition; Odoo nutzt das für die Forderungen und das Kreditlimit des Kontakts (Buchhaltungsgruppen) | braucht eine Definition am Feld, etwa im eigenen Modul |
| Sichtbarkeit in der Ansicht (Studio) | die Anzeige eines Elements in dieser Ansicht | Benutzer ohne die gewählte Gruppe | Studio, Feld-Eigenschaften für die Sichtbarkeit von Gruppen; alternativ das Attribut groups in der Ansicht | kein Feldzugriff: laut Entwicklerdokumentation 20.0 wird das Element nur für Benutzer ohne die Gruppe nicht angezeigt |
| Einschränkung ohne Gruppe (globale Datensatzregel) | Datensätze, welche die Domäne nicht erfüllen | alle Benutzer, auch Administratoren | Einstellungen ▸ Technisch ▸ Sicherheit ▸ Zugriffsrechte, Feld Gruppe leer lassen | eine Gruppenberechtigung kann sie nicht lockern; nur der Superuser-Modus umgeht sie |
| Portalbenutzer statt internem Benutzer | alle Kontakte außer dem eigenen kommerziellen Partner und dessen untergeordneten Kontakten | externe Kunden und Lieferanten | im Kontakt unter Aktionen ▸ Portalzugriff gewähren | laut Community-Quellcode 20.0 liest die Domäne mit child_of den kommerziellen Partner und dessen untergeordnete Kontakte; kein Backend-Zugriff |
| Archivieren | nichts | alle Benutzer | Kontakt auswählen, Aktionen ▸ Archivieren | der Filter Archiviert zeigt die Kontakte weiter (Dokumentation 20.0) |
| Berechtigungen Kontakt ▸ Erstellung und Export ▸ Erlaubt | Anlegen und Löschen von Kontakten sowie den Datenexport | interne Benutzer ohne diese Berechtigungen | Einstellungen ▸ Benutzer & Unternehmen ▸ Benutzer, Reiter Zugriffsrechte | ändert die Sichtbarkeit nicht; ohne Export ▸ Erlaubt bricht der Export im Quellcode 20.0 mit einer Fehlermeldung ab, außer für Benutzer im Administrationszugriff Zugriffsrechte (env.is_admin()) |
Mehrere Unternehmen lösen im Plan Standard laut Dokumentation 20.0 ein Upsell auf den Plan Custom aus – bei jährlichen oder mehrjährigen Verträgen mit 30 Tagen Frist, bei monatlicher Abrechnung mit automatischem Wechsel; für Datenbanken im Tarif Eine App Gratis nennt dieselbe Seite eine Ausnahme.
Beim Feld Unternehmen kommt die Unternehmenshierarchie hinzu, die die Dokumentation 20.0 unter Companies ▸ Branches beschreibt: Zweigstellen stehen unter einer gemeinsamen Muttergesellschaft, auch mehrstufig. Laut Community-Quellcode 20.0 prüft die Datensatzregel des Kontaktmodells mit parent_of, nicht auf Gleichheit; ein Kontakt bleibt deshalb auch sichtbar, wenn sein Unternehmen einem aktivierten Unternehmen übergeordnet ist – wer nur eine Zweigstelle aktiviert hat, sieht die Kontakte der Muttergesellschaft –, und ebenso, wenn er keinem Unternehmen zugeordnet ist (Feld leer) oder mit einem internen Benutzer verknüpft ist (partner_share = False).
Was der Datenschutz dazu verlangt
Kontaktdaten natürlicher Personen sind personenbezogene Daten. In Deutschland und Österreich verlangt Art. 32 Abs. 1 DSGVO von Verantwortlichen und Auftragsverarbeitern geeignete technische und organisatorische Maßnahmen für ein dem Risiko angemessenes Schutzniveau; die Verordnung ist seit 25. Mai 2018 anzuwenden, und die Aufzählung der Buchstaben a bis d ist nach der berichtigten Fassung nicht abschließend. In der Schweiz verlangt Art. 8 Abs. 1 DSG (in Kraft seit 1. September 2023) eine dem Risiko angemessene Datensicherheit durch geeignete technische und organisatorische Massnahmen; Abs. 2 verlangt, dass diese Massnahmen Verletzungen der Datensicherheit vermeiden.
Das Verbergen von Kontakten ist eine mögliche Massnahme; welche angemessen ist, hängt von den Daten und dem Risiko ab. Klären Sie die Bewertung mit Ihrer Datenschutzberatung.
Ein durchgerechnetes Beispiel: ein Stichwort Vertraulich
Das Beispiel ist ein redaktioneller Vorschlag nach dem Muster der Verkaufsregel sale_order_personal_rule (Quellcode 20.0). Angenommen, Sie markieren vertrauliche Kontakte mit dem Stichwort Vertraulich und tragen im Feld Vertriebsmitarbeiter die Person ein, die sie sehen darf. Legen Sie dann im Entwicklermodus unter Einstellungen ▸ Technisch ▸ Sicherheit ▸ Zugriffsrechte einen Eintrag an:
- Name: Vertrauliche Kontakte
- Modell: res.partner
- Gruppe: leer (Einschränkung, gilt für alle Benutzer)
- Vorgänge: Erstellen, Lesen, Aktualisieren, Löschen
- Bereich (Domain): [‘|’, (‘category_id’, ‘not in’, [ID des Stichworts]), (‘user_id’, ‘=’, user.id)]
Die Dokumentation 20.0 nennt solche Bedingungen Record Rules (Datensatzregeln) und verortet sie im Gruppenformular; im Community-Quellcode 20.0 ist die Liste Zugriffsrechte der Ort dafür. Tragen Sie für die ID die Zahl ein, die Odoo dem Stichwort gibt; die Variable user ist laut Entwicklerdokumentation 20.0 in Domänen verfügbar. Die Wirkung im Beispiel:
| Benutzer | Kontakt mit dem Stichwort Vertraulich | Vertriebsmitarbeiter | Ergebnis |
|---|---|---|---|
| Anna | ja | Anna | sichtbar |
| Ben | ja | Anna | nicht sichtbar, auch in Suche und Kanban |
| Carla (Administratorin) | ja | Anna | nicht sichtbar; Einschränkungen gelten für alle Benutzer |
| Dirk | nein | ohne Eintrag | sichtbar |
Weil die Regel eine Einschränkung ohne Gruppe ist, gilt sie für alle Benutzer: Wer die vertraulichen Kontakte sehen soll, muss als Vertriebsmitarbeiter im Kontakt stehen. Prüfen Sie mit einem Testbenutzer Belege, Berichte, E-Mail-Versand und Adressen auf fehlende Kontakte.
Typische Fehler
- Eine Regel mit Gruppe als Schutz erwarten. Sie fügt eine bedingte Erlaubnis hinzu; die unbedingte Erlaubnis der internen Benutzer bleibt wirksam, weil Zugriffsrechte additiv sind. Die globale Unternehmensregel schneidet daneben weiter.
- Ein Feld in einer Ansicht ausblenden und für geschützt halten. Das Attribut groups blendet das Element in dieser Ansicht aus; den Feldzugriff entfernt erst das Attribut an der Felddefinition. Prüfen Sie Listen, Berichte und den Export.
- Einen Kontakt archivieren und für verborgen halten. Der Filter Archiviert in der Suche zeigt ihn weiter (Dokumentation 20.0).
- Erwarten, dass das Feld Unternehmen einen Kontakt verbirgt. Die Unternehmensregel lässt laut Community-Quellcode 20.0 Kontakte ohne Unternehmen, Kontakte eines übergeordneten Unternehmens und Kontakte mit verknüpftem internem Benutzer sichtbar.
- Annehmen, eine Administratorin sehe alles. Eine Einschränkung ohne Gruppe gilt auch für sie; nur der Superuser-Modus umgeht Regeln und Zugriffsrechte.
- Nur die Sichtbarkeit betrachten. Wer einen Kontakt sehen darf, kann seine Angaben abschreiben; der Datenexport ist im Quellcode 20.0 zusätzlich an die Berechtigung Export ▸ Erlaubt gebunden, ausgenommen Benutzer im Administrationszugriff Zugriffsrechte (env.is_admin()). Dass Verwaltungsgruppen einzelner Apps Kontakte ändern dürfen, prüfen Sie zusätzlich.
So gehen Sie vor
- Entscheiden Sie, was geschützt werden soll: ganze Kontakte oder einzelne Felder.
- Prüfen Sie in einer Testdatenbank die Gruppen Ihrer Benutzer; Zugriffsrechte ändern darf nur ein Administrator.
- Wählen Sie den Weg aus der Tabelle: das Feld Unternehmen für Einheiten, die nicht unter einer gemeinsamen Muttergesellschaft stehen, groups am Feld für einzelne Angaben, eine Einschränkung ohne Gruppe für vertrauliche Kontakte.
- Legen Sie die Regel im Entwicklermodus an und prüfen Sie sie mit zwei Testbenutzern in Liste, Suche, Belegen und Berichten.
- Prüfen Sie die Berechtigungen Kontakt ▸ Erstellung und Export ▸ Erlaubt für alle internen Benutzer.
- Halten Sie Stichwörter, Vertriebsmitarbeiter und Unternehmenszuordnung nach, sonst greift die Regel nicht.
Zur Benutzerverwaltung und zu den Gruppen: Benutzer anlegen und Gruppen zuweisen. Die Regeln selbst beschreibt Datensatzregeln in Odoo mit einem durchgerechneten Beispiel für Filialen.