Ce que tu vas apprendre
Distinguer les types d'utilisateurs
Interne, portail, public — la frontière de licence côté Enterprise et le champ share calculé en Community. Quand créer chaque type, et quand surtout pas.
Lire la nouvelle hiérarchie v19
Catégorie → Privilège → Groupe — le breaking change v19 qui remplace l'ancien category_id sur res.groups. Comment l'UI affiche cette nouvelle structure.
Comprendre ACL et règles
Lire la matrice ir.model.access, distinguer une règle globale d'une règle locale par groupe, et croiser droits + multi-société sans tout casser.
1. Trois types d'utilisateurs, une seule table
Tous les utilisateurs Odoo vivent dans la même table res.users. Ce qui change d'un type à l'autre, c'est l'appartenance à un groupe technique précis :
- Utilisateur interne — appartient au groupe
base.group_user. Il a accès au backend Odoo (la zone d'administration violette en haut), aux apps installées, et il consomme une licence côté Enterprise. En Community, pas de comptage de licence — mais la séparation reste structurante. - Utilisateur portail — appartient au groupe
base.group_portal. Il accède uniquement à son espace client en frontend (/my), voit ses propres documents (devis, factures, tickets), commente, télécharge. Aucun accès backend. - Utilisateur public — appartient à
base.group_public. C'est l'utilisateur anonyme qui parcourt le site web sans être connecté. Une seule instance par base.
Le champ share (booléen calculé) tranche net : True pour portail et public, False pour les internes. Côté code, c'est ce champ qui sert de garde-fou partout où la logique métier ne doit s'appliquer qu'aux utilisateurs internes.
Côté UI, la liste des utilisateurs filtre par défaut sur les internes. C'est ce que montre le formulaire de listage standard, accessible via Paramètres → Utilisateurs & Sociétés → Utilisateurs :
role à partir des groupes effectivement assignés.⚠️ Piège — créer un client en utilisateur interne
Erreur fréquente sur les bases jeunes : créer un compte client comme utilisateur interne « pour aller vite ». Conséquence : ce contact accède au backend complet, voit toutes les commandes de toutes les sociétés (sauf règles d'enregistrement, voir §4), et consomme une licence côté Enterprise. La bonne réponse : un compte portail rattaché au partenaire client, qui n'a accès qu'à /my.
2. La nouvelle hiérarchie Catégorie → Privilège → Groupe (breaking change v19)
Jusqu'à la version 18, un groupe Odoo (res.groups) portait directement un champ category_id qui le rattachait à une catégorie de module (l'app Ventes, l'app Comptabilité, etc.). L'affichage des groupes dans la liste se faisait sous la forme Catégorie / Nom, par exemple Sales / User.
La version 19 insère un niveau intermédiaire : le privilège. Un nouveau modèle res.groups.privilege regroupe désormais plusieurs groupes liés. Le champ category_id a disparu de res.groups — il appartient maintenant au privilège. La chaîne devient :
(ex: Sales) (ex: Sales Access) (ex: User / Manager)
Côté UI, la liste des groupes (mode développeur activé, Paramètres → Technique → Sécurité → Groupes) affiche maintenant deux colonnes : Droit (le privilège) et Nom (le groupe lui-même) :
Ouvrir un groupe en formulaire fait apparaître clairement le champ privilege_id et l'onglet Hérité qui pointe vers d'autres groupes (champ implied_ids) — un groupe peut en hériter plusieurs, ce qui permet à un Administrateur Ventes d'avoir d'office tous les droits d'un Utilisateur Ventes :
📖 Définition — implied_ids
Un groupe peut impliquer d'autres groupes via implied_ids. Donner Ventes / Administrateur à un utilisateur lui accorde automatiquement Ventes / Utilisateur, et toutes les permissions transitives via le champ calculé all_implied_ids. C'est la façon propre de modéliser des rôles cumulatifs sans dupliquer les ACL.
3. Le formulaire utilisateur v19 — édition par privilèges, plus par groupes
Conséquence directe de la nouvelle hiérarchie : le formulaire utilisateur n'expose plus les groupes un par un, mais par section privilège. Chaque section affiche les groupes du privilège sous forme de sélection ou de radio, avec un champ placeholder (« No », « Créer », « View »…) qui rend lisible l'absence d'attribution.
Ouvrir le compte administrateur sur l'onglet Droits d'accès illustre la mécanique : les privilèges (Ventes, Projet, Comptabilité, Achats, Fabrication, eLearning, Site Web…) deviennent des sections lisibles, le rôle global se règle en une radio Utilisateur / Administrateur, et les sociétés autorisées apparaissent en tags colorés :
Cette refonte UI résout un vieux problème : avant v19, un admin fonctionnel devait connaître par cœur les noms techniques des groupes pour cocher la bonne combinaison. Maintenant, chaque section affiche un choix exclusif ou cumulatif, avec un libellé métier lisible. Le clic se limite à une sélection par privilège.
🎯 À retenir — le rôle est calculé
Le champ role sur l'utilisateur n'est pas stocké en dur. Il est calculé depuis group_ids : Administrateur si l'utilisateur appartient à base.group_system, Utilisateur sinon. Cocher le radio bascule discrètement l'appartenance au groupe technique. C'est utile pour piloter des règles ou des automatisations conditionnées au rôle effectif.
4. La matrice ACL — droits CRUD par modèle et par groupe
Le modèle ir.model.access matérialise la matrice des permissions CRUD : qui peut lire, écrire, créer, supprimer quel modèle de données. C'est le premier filtre que franchit toute requête ORM Odoo.
Chaque ligne ACL porte cinq champs essentiels :
model_id— le modèle ciblé (ex:sale.order,account.move,res.partner).group_id— le groupe concerné. SiNULL, la ligne s'applique à tous les utilisateurs internes.perm_read,perm_write,perm_create,perm_unlink— quatre booléens CRUD.
Côté UI (toujours en mode développeur), Paramètres → Technique → Sécurité → Droits d'accès permet de filtrer par modèle et de lire la matrice. Filtrer sur sale.order donne typiquement une dizaine de lignes, une par groupe :
sale.order. Une ligne par groupe : Ventes / Administrateur ouvre tout (R/W/C/D), Projet / Utilisateur n'a que la lecture, Comptabilité / Facturation n'a aussi que la lecture, et ainsi de suite.⚠️ Piège — ACL avec group_id IS NULL
Une ligne ACL avec group_id vide et perm_read=True ouvre la lecture du modèle à tous les utilisateurs internes, indépendamment de leurs groupes app. C'est un raccourci pratique pour des modèles transverses (devises, pays, sociétés…) mais c'est aussi un piège quand on cherche à restreindre un modèle métier. Vérifier l'absence d'une telle ligne avant d'écrire ses propres ACL.
Côté code, ces lignes sont définies dans le fichier security/ir.model.access.csv de chaque module. Format CSV minimaliste : id, name, model_id:id, group_id:id, perm_read, perm_write, perm_create, perm_unlink. Écrire des ACL personnalisées pour un module custom revient à éditer ce CSV et déclarer le fichier dans le __manifest__.py.
5. Les règles d'enregistrement — globales vs locales
Une fois la matrice ACL franchie, un second filtre s'applique : les règles d'enregistrement (ir.rule). Ce sont des domaines Python qui restreignent quels enregistrements un utilisateur peut voir au sein d'un modèle, même s'il a le droit CRUD général.
La règle clé pour le multi-société : sur la plupart des modèles métier, Odoo installe une règle globale Multi-Company qui filtre company_id in user.company_ids. Sans cette règle, un utilisateur multi-société verrait toutes les factures, toutes les commandes, tous les contrats — même hors de ses sociétés autorisées. C'est cette règle, par exemple, qui filtre les écritures comptables :
account.move. Globale cochée (aucun groupe rattaché), domaine [('company_id', 'in', company_ids)], droits CRUD tous validés. Le bloc d'aide officiel rappelle l'algorithme : règles globales en AND, règles par groupe en OR.Distinction critique :
- Règle globale (champ
groupsvide, booléen calculéglobal=True) — s'applique à tout le monde. Plusieurs règles globales se combinent en ET logique (intersection des résultats). C'est un filtre dur, impossible à contourner par appartenance à un groupe. - Règle locale (champ
groupsrempli) — s'applique aux utilisateurs des groupes listés. Les règles locales d'un même utilisateur se combinent en OU logique entre groupes (union des résultats). C'est un filtre additif, qui élargit le champ du visible.
L'algorithme final est : (globales en AND) AND (union OR des locales par groupe applicable). La règle multi-société est globale par construction — c'est pourquoi elle s'impose même aux administrateurs métier.
⚠️ Piège — désactiver une règle globale
Désactiver le booléen active d'une règle globale multi-société « pour résoudre un bug » ouvre la fuite de données entre sociétés. La règle est globale pour une raison : c'est elle qui fait tenir l'isolation. La bonne approche en cas de besoin légitime de cross-société, c'est l'écriture d'une règle locale par groupe.
6. Multi-société + groupes — l'exemple d'un comptable restreint
Croiser les deux axes (sociétés autorisées + groupes métier) donne une matrice de droits effective. Cas d'usage typique : un comptable affecté à une seule société du groupe, qui n'a accès qu'au privilège Comptabilité au niveau Facturation.
Le formulaire utilisateur correspondant montre les deux dimensions d'un coup : un seul tag dans Sociétés, et un seul privilège significativement activé dans la grille :
Trois conséquences pratiques :
- Ce compte ne voit jamais les écritures comptables des trois autres sociétés du groupe, même si quelqu'un lui partage un lien direct vers une facture étrangère. La règle globale Account Entry (cf. §5) filtre la requête au niveau base.
- Ce compte ne voit pas l'app Ventes, car son privilège Ventes est à No. Le menu d'app n'apparaît même pas dans le launcher.
- Ce compte voit néanmoins les modèles transverses partagés (devises, pays, sociétés, partenaires de base) — ce sont des dépendances structurelles, pas une fuite de droits métier.
C'est cette combinaison qui rend le natif Community puissant : trois leviers (groupes, sociétés autorisées, règles d'enregistrement) suffisent à modéliser 80 % des cas d'usage d'une PME structurée.
7. Au-delà du natif — la frontière premium
Tout ce qui précède tient sur le natif Community Edition. Plusieurs sujets restent volontairement hors de ce cadrage, parce qu'ils méritent une couverture approfondie :
- Règles d'enregistrement complexes — restreindre la visibilité selon le partenaire, l'équipe commerciale ou des conditions combinées. Cas typique : un commercial ne voit que ses propres devis ou ceux de son équipe.
- ACL fines croisées multi-société — restreindre la création de factures sur certaines sociétés tout en autorisant la lecture sur d'autres, sans casser les workflows natifs.
- Valeurs dépendantes de la société — un même partenaire avec un IBAN différent par société, un même produit avec un prix différent par filiale.
- Audit de sécurité multi-société — vérifier qu'aucun raccourci ne contourne les règles d'isolation entre sociétés.
- Industrialisation des groupes et privilèges — rôles hiérarchiques et automatisation des droits à l'échelle d'un déploiement.
Le présent article suffit néanmoins pour démarrer proprement une PME multi-société et résister aux deux ou trois premières années sans dette technique.
8. Checklist setup utilisateurs & droits
À appliquer dès la création d'une nouvelle base Odoo CE, avant d'inviter le premier utilisateur métier :
- Ne jamais créer un client en utilisateur interne — toujours un compte portail rattaché au partenaire.
- Réserver le rôle Administrateur à 1 ou 2 comptes techniques — pas aux opérationnels métier, qui se contentent du rôle Utilisateur + des privilèges nécessaires.
- Affecter explicitement les sociétés autorisées sur chaque utilisateur. Ne pas laisser
company_idspar défaut quand la base est multi-société. - Vérifier les ACL
group_id IS NULLsur les modèles métier sensibles (factures, contrats, fiches RH) avant d'ajouter des règles d'enregistrement. - Ne jamais désactiver une règle d'enregistrement globale sans une analyse complète de l'impact multi-société.
- Documenter les groupes custom créés dans un fichier dédié — un groupe orphelin sans documentation devient une dette de sécurité au bout de six mois.
🎯 À retenir
Trois leviers natifs Community suffisent : (1) le type d'utilisateur (interne / portail / public), (2) la combinaison privilèges + sociétés autorisées sur le compte, (3) les règles d'enregistrement globales pour l'isolation multi-société. Tout ce qui ne tient pas dans ces trois leviers relève soit du custom (et alors d'un module dédié avec ses ACL CSV), soit du sujet premium.
Voir aussi dans le hub Configuration
Saison 12 · ADM·1
Multi-société dans Odoo 19 Community
Le prérequis : créer plusieurs sociétés, hiérarchie parent/filiale, switcher topbar.
Saison 1 · F45
Les ventes dans Odoo 19
Comment les groupes Ventes filtrent les devis et commandes en multi-société.
Saison 2 · F48
Facturation et paiements dans Odoo 19
Les règles d'isolation comptable en pratique sur account.move.
Pour aller plus loin côté technique
- Blog Technique Odoo — articles sur les ACL CSV custom, les
ir.ruleavancées et les domaines Python. - Hub Configuration du blog fonctionnel — toute la série Administrer Odoo 19 CE et les fondamentaux multi-société.