[DTP-Worker] Sprint 2 · ERPNext RBAC 50 rôles (schéma + data + spec + gate)
Livrable Sprint 2 (roadmap §S2 l.38 « RBAC 50 rôles configuration », GAP_ANALYSIS §3.4). Seul deliverable S2 100% autorable en-repo — les clones Frontend/CRM dépendent des layouts LIVE (VPS). - rbac/rbac.schema.json — contrat JSON-Schema draft-07 (sous-ensemble validateur maison, zéro pip) : 50 rôles, DocPerm par DocType, scope User Permission. - rbac/rbac_50_roles.json — 50 rôles × 5 portails métier + console plateforme, mappés aux entités CLAUDE.md, ciblant des DocTypes ERPNext v15 natifs. - rbac/RBAC_50_ROLES_SPEC.md — design RBAC 3 niveaux + séparation des pouvoirs + procédure d'application VPS (fixtures bench, hors périmètre worker). - rbac/tests/test_rbac.py — 10 tests unittest (réutilise le validateur Publiciste, pas de doublon) : 50 rôles exacts, unicité, 5 portails, anti- élévation de privilège. Oracle jsonschema si présent. - ci.yml — job rbac-tests ajouté au gate (Gitea Actions uniquement). - GAP_ANALYSIS §3.4 + daily report 2026-07-30 (session 4) mis à jour. Anti-invention #6 : aucun plafond monétaire inventé ; DocTypes non natifs marqués custom → à confirmer VPS. Gate local vert (guard/json/docs + 10 tests RBAC + 23 tests Publiciste régression). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -83,9 +83,9 @@ et la cible plancher **4-5 semaines**.
|
||||
|
||||
### 4 · ERPNext Backend Agent — 🟡 Refactor (gain ~35 %)
|
||||
- **Existe** : site `frontend` (`erpnext-backend-1`), apps `otov7_platform` + `otov7_construction` + `erpnext` v15.112 + `frappe` v15.112, modules `crm/ crm_native/ api/ config/ audit_console.py`.
|
||||
- **Gap** : RBAC 50 rôles non configuré ; e-CF DGII (Compupar) non intégré ; commissions vendeurs auto absentes ; DocType « Faisabilité » (version + score) manquant.
|
||||
- **À faire** : cartographie DocTypes (⚠ à confirmer VPS) → RBAC 50 rôles → e-CF → workflows.
|
||||
- **Sprint** : S2 (RBAC) → S4 (e-CF + commissions).
|
||||
- **Gap** : ~~RBAC 50 rôles non configuré~~ → **design livré S2** (`rbac/` : `rbac_50_roles.json` + `rbac.schema.json` + spec + 10 tests) ; application fixtures = VPS ; e-CF DGII (Compupar) non intégré ; commissions vendeurs auto absentes ; DocType « Faisabilité » (version + score) manquant.
|
||||
- **À faire** : cartographie DocTypes (⚠ à confirmer VPS) → ✅ RBAC 50 rôles (design) → application fixtures VPS → e-CF → workflows.
|
||||
- **Sprint** : S2 (RBAC ✅ design) → S4 (e-CF + commissions).
|
||||
|
||||
### 5 · Frontend Console Agent — 🟡 Refactor (gain ~55 %)
|
||||
- **Existe** : `portal/*.html`, pages Frappe `www/` (wag-home, waf-home, pole/, projets/), tokens luxury `#0a0a12`/`#f0b429` (Fraunces + Cormorant Garamond), 5 logos officiels.
|
||||
|
||||
@@ -139,3 +139,49 @@ Rapport écrit dans `05_deliverables_mvp/daily_reports/` (chemin canonique fixé
|
||||
---
|
||||
|
||||
**Auto-score 4Big du livrable Publiciste (parser) : 95/100.** Réserve −5 : exécution contre `data_room/` réel différée (VPS) ; triggers/notifications/EN-ES = livrables Semaines 4-6 ; validé statiquement en-repo (23 tests verts + gate CI vert + schéma conforme).
|
||||
|
||||
---
|
||||
|
||||
# Daily Report · 2026-07-30 · Claude Code DTP Worker (session 4)
|
||||
|
||||
**Session** : `20260730_015634`
|
||||
|
||||
## Tâche exécutée
|
||||
**Sprint 2 · Livrable ERPNext Backend « RBAC 50 rôles »**
|
||||
(roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` §Sprint 2 l.38 · `GAP_ANALYSIS_SPRINT1` §3.4 · suggérée par session 3).
|
||||
|
||||
## Contexte / analyse
|
||||
- Relu `CLAUDE.md`, `ROADMAP_8_WEEKS_OR_LESS.md`, `GAP_ANALYSIS_SPRINT1.md`, daily reports sessions 1-3, `AGENT.md` ERPNext Backend + Frontend Console, `AGENTS_EXISTING_ASSETS.md` §4-6, `projets_master.schema.json`, `validator.py`, `ci.yml`.
|
||||
- **Sprint 1 bouclé côté repo** ; Sprint 2 : 3 deliverables. Frontend (clone 5 entités) + CRM (pipeline) dépendent des layouts LIVE `/waf-home` / `/crm.html` (VPS). **RBAC 50 rôles = seul deliverable S2 100 % autorable en-repo** comme spec de conception machine-lisible → priorité évidente. Dépendance amont des 5 portails rôle (S4) et du workflow vente.
|
||||
|
||||
## Réalisé — module `05_deliverables_mvp/rbac/`
|
||||
- `rbac.schema.json` — contrat JSON-Schema draft-07 (sous-ensemble supporté par le validateur maison, **zéro pip**) : 50 rôles, `id` kebab, `erpnext_role_name` préfixe `OTO `, `permissions_cibles[]` (DocType + verbes Frappe), `scope_donnees` (own/equipe/entite/groupe), `cible_rbac_roles` const 50.
|
||||
- `rbac_50_roles.json` — **50 rôles** répartis sur 5 portails métier (roadmap S4) + 1 console technique (`plateforme`), mappés aux **entités CLAUDE.md** (WAF/WA SRL/AC Arias Cuevas/Consortium ECR DR/Helios RD/Ploutos/9060 QC/Groupe). Permissions ciblant des **DocTypes ERPNext v15 natifs** (Lead/Opportunity/Quotation/Sales Order/Purchase Order/Journal Entry/Salary Slip…) + DocTypes DTP marqués `custom: true` (à confirmer VPS).
|
||||
- `RBAC_50_ROLES_SPEC.md` — design : modèle RBAC 3 niveaux (Role · DocPerm · User Permission), cartographie portails/familles/entités, conformité contraintes #1/#3/#6/#8, **séparation des pouvoirs** (`set_user_permissions` réservé au RBAC Admin), procédure d'application VPS (fixtures `bench`, hors périmètre worker).
|
||||
- `tests/test_rbac.py` — **10 tests `unittest` (stdlib)** : **réutilise le validateur Publiciste** (pas de duplication · workflow #5) + oracle `jsonschema` si présent ; vérifie exactement 50 rôles, unicité `id`/nom Frappe, couverture des 5 portails, anti-élévation de privilège.
|
||||
- **CI** : job `rbac-tests` ajouté au **gate** de `.gitea/workflows/ci.yml` (Gitea Actions uniquement · #2).
|
||||
- `GAP_ANALYSIS_SPRINT1.md` §3.4 mis à jour (RBAC design livré S2).
|
||||
|
||||
## Anti-invention (#6) appliqué
|
||||
- **Aucun chiffre/plafond monétaire inventé** : seuls rôles, entités et DocTypes natifs. Plafonds d'approbation volontairement non chiffrés (à définir avec la Direction sur pièces).
|
||||
- DocTypes non natifs marqués `custom: true` → **existence à confirmer VPS** avant application (respect de l'interdit « documenter code sans vérifier existence courante »).
|
||||
|
||||
## Vérifications effectuées (en-repo, sans toucher au VPS)
|
||||
- **10/10 tests RBAC verts** (schéma maison **+** oracle `jsonschema` installé → concordance draft-07 confirmée).
|
||||
- **Gate CI local vert (exit 0)** : `guard_constraints.sh`, `validate_json.sh` (inclut `rbac_50_roles.json`), `check_docs.sh` (0 lien cassé ; spec RBAC porte son auto-score 4Big).
|
||||
- **Régression** : 23/23 tests Publiciste toujours verts (réutilisation du validateur sans effet de bord).
|
||||
|
||||
## Non fait (hors périmètre worker · touche au VPS)
|
||||
- Génération + application des **fixtures `Role`/`Custom DocPerm`** sur `erpnext-backend-1` (`bench migrate`) → agent ERPNext Backend.
|
||||
- Création des DocTypes DTP `custom` (`Faisabilité`, `Publiciste Log`, `CONFOTUR Application`, `API Access`) après confirmation VPS.
|
||||
- Mapping `scope_donnees` → `User Permission` par utilisateur → VPS.
|
||||
- Cartographie DocTypes réels `otov7_platform` (dernier critère S1) → ERPNext sur VPS.
|
||||
|
||||
## Prochaine tâche suggérée
|
||||
- ERPNext S2 : **générateur de fixtures** `rbac_50_roles.json → fixtures/` (même patron que le Publiciste, autorable en-repo).
|
||||
- Ou Faisabilité S2 : générateur 4 volets auto consommant le template v1.0 (produit les `data_room/PXX/` consommés par le parser Publiciste).
|
||||
- Ou Frontend/CRM S2 : nécessite les layouts LIVE (VPS) → hors périmètre worker.
|
||||
|
||||
---
|
||||
|
||||
**Auto-score 4Big du livrable RBAC 50 rôles : 95/100.** Réserve −5 : application fixtures + DocTypes `custom` + `User Permission` = côté VPS (agent ERPNext, hors périmètre) ; plafonds monétaires non chiffrés (anti-invention #6). Validé statiquement en-repo (10 tests verts + schéma conforme + gate CI vert).
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Artefacts Python (jamais commit — reproductibles).
|
||||
__pycache__/
|
||||
*.pyc
|
||||
# Fixtures Frappe générées côté VPS (hors périmètre worker).
|
||||
fixtures/
|
||||
@@ -0,0 +1,152 @@
|
||||
# Spec RBAC · 50 rôles · OTO Enterprise OS DTP
|
||||
|
||||
> **Livrable Sprint 2 · ERPNext Backend** (roadmap
|
||||
> [`../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md`](../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md)
|
||||
> §Sprint 2 l.38 : _« ERPNext Backend : RBAC 50 rôles configuration »_ ·
|
||||
> [`../GAP_ANALYSIS_SPRINT1.md`](../GAP_ANALYSIS_SPRINT1.md) §3.4 gap ERPNext).
|
||||
>
|
||||
> **Date** : 2026-07-30 · **Auteur** : Claude Code DTP Worker · **Version** : 1.0.0
|
||||
|
||||
---
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Design **machine-lisible** des **50 rôles RBAC** (contrainte CLAUDE.md « RBAC 50 rôles »)
|
||||
à créer nativement dans Frappe/ERPNext v15. Le contrat de données est
|
||||
[`rbac.schema.json`](rbac.schema.json) ; les données sont
|
||||
[`rbac_50_roles.json`](rbac_50_roles.json). Ce document ne touche **jamais la
|
||||
production** : il définit la **cible** que l'agent ERPNext Backend appliquera sur
|
||||
le VPS via `bench` / fixtures (voir §7).
|
||||
|
||||
**Priorité ERPNext natif** (contrainte #1) : chaque rôle est un DocType `Role`
|
||||
Frappe standard — **aucun** RBAC externe.
|
||||
**CRM = ERPNext natif** (jamais EspoCRM ni HubSpot — contrainte #3).
|
||||
|
||||
## 2. Modèle RBAC
|
||||
|
||||
Le RBAC Frappe combine trois niveaux, tous couverts par le schéma :
|
||||
|
||||
| Niveau Frappe | Champ du schéma | Rôle |
|
||||
|---|---|---|
|
||||
| **Role** (DocType) | `erpnext_role_name` | Un DocType `Role` par ligne, préfixe `OTO ` (anti-collision natif). |
|
||||
| **Permissions par DocType** | `permissions_cibles[]` | Verbes Frappe (`read`/`write`/`create`/`submit`/`cancel`/`report`/…) par DocType. |
|
||||
| **Row-level** (User Permission) | `scope_donnees` | `own` · `equipe` · `entite` (Company) · `groupe` (consolidé). |
|
||||
|
||||
**Défense en profondeur** : le pouvoir `set_user_permissions` (gestion des
|
||||
habilitations) est **réservé** au seul rôle `OTO Plateforme RBAC Admin`
|
||||
(`scope_donnees = groupe`, `famille = plateforme`) — séparation des pouvoirs
|
||||
vérifiée par test automatisé.
|
||||
|
||||
## 3. Cartographie portails ↔ familles
|
||||
|
||||
Les **5 portails métier** (roadmap Sprint 4 « 5 portails rôle ») + **1 console
|
||||
technique transversale** (`plateforme`, hors du compte de 5) :
|
||||
|
||||
| Portail | Familles rattachées | Nb rôles |
|
||||
|---|---|---|
|
||||
| **direction** | direction, finance (CFO), faisabilite (analyste), legal | 10 |
|
||||
| **ventes** | ventes, marketing | 12 |
|
||||
| **construction** | construction, faisabilite (rendu/IFC/économiste) | 10 |
|
||||
| **achat** | achat | 5 |
|
||||
| **compta** | finance | 8 |
|
||||
| **plateforme** _(technique)_ | plateforme | 5 |
|
||||
| | **Total** | **50** |
|
||||
|
||||
> Répartition indicative issue de `rbac_50_roles.json` ; la source de vérité reste
|
||||
> le JSON (le test impose exactement 50 rôles et la couverture des 5 portails).
|
||||
|
||||
## 4. Cartographie rôles ↔ entités (CLAUDE.md §Entités)
|
||||
|
||||
Chaque rôle porte une `entite_principale`. « Groupe » = périmètre consolidé
|
||||
transversal (direction, contrôle de gestion, audit UAF, BI).
|
||||
|
||||
| Entité | Exemples de rôles |
|
||||
|---|---|
|
||||
| **WAF** (holding) | Président, Directeur Juridique, Agent ONAPI |
|
||||
| **WA SRL** | Contrats de vente, Achats, Comptable général, Fiscaliste e-CF, Analyste faisabilité |
|
||||
| **AC Arias Cuevas** | Directeur/Chef de projet Construction, Ingénieur, Économiste, Magasinier |
|
||||
| **Consortium ECR DR** (paymaster RH) | Gestionnaire Paie |
|
||||
| **Helios RD** (marque publique) | Directeur des Ventes, Conseiller, Marketing, Comptable clients AR |
|
||||
| **Ploutos** (patrimoine/monétaire) | Trésorier |
|
||||
| **9060 QC** (World Activities Cdn.) | DevOps, RBAC Admin, QA, OTOIA, Mobile |
|
||||
| **Groupe** (consolidé) | DG, CFO, COO, CCO, Conseil, Contrôle de gestion, Audit UAF, BI |
|
||||
|
||||
## 5. Les 50 rôles (résumé)
|
||||
|
||||
> Détail complet (permissions par DocType, modules, scope) dans
|
||||
> [`rbac_50_roles.json`](rbac_50_roles.json).
|
||||
|
||||
**Direction / Gouvernance (6)** — Président WAF · Directeur Général · CFO · COO ·
|
||||
CCO · Conseil d'Administration (lecture).
|
||||
|
||||
**Ventes (8)** — Directeur des Ventes · Chef d'Équipe · Conseiller · Courtier
|
||||
externe · Coordinateur Réservations · Gestionnaire Contrats · Coordinateur
|
||||
CONFOTUR · Support Après-Vente.
|
||||
|
||||
**Marketing (4)** — Directeur Marketing · Publiciste (agent) · SEO · Social.
|
||||
|
||||
**Construction (7)** — Directeur · Chef de Projet · Ingénieur · Architecte ·
|
||||
QA/QC · Coordinateur BIM · Superviseur Sous-traitants.
|
||||
|
||||
**Achat (5)** — Directeur · Acheteur · Gestionnaire Fournisseurs · Magasinier ·
|
||||
Contrôleur Réception.
|
||||
|
||||
**Finance / Compta (8)** — Contrôleur de Gestion · Comptable Général · AP · AR ·
|
||||
Trésorier (Ploutos) · Paie (Consortium ECR DR) · Fiscaliste e-CF · Audit UAF.
|
||||
|
||||
**Faisabilité / AEC (4)** — Analyste Faisabilité · Rendu 3D · IFC/Speckle ·
|
||||
Économiste de la Construction.
|
||||
|
||||
**Legal (2)** — Directeur Juridique · Agent ONAPI.
|
||||
|
||||
**Plateforme technique (6)** — DevOps · RBAC Admin · QA · OTOIA (système) ·
|
||||
Mobile · BI.
|
||||
|
||||
_(6+8+4+7+5+8+4+2+6 = 50.)_
|
||||
|
||||
## 6. Conformité aux contraintes CLAUDE.md
|
||||
|
||||
| # | Contrainte | Application ici |
|
||||
|---|---|---|
|
||||
| 1 | ERPNext natif prioritaire | 100 % DocType `Role` Frappe, aucun RBAC externe. |
|
||||
| 3 | CRM = ERPNext natif | Rôles ventes → `Lead`/`Opportunity`/`Quotation`/`Customer` natifs. |
|
||||
| 6 | Zéro invention | Aucun chiffre/plafond monétaire inventé ; seuls rôles, entités et DocTypes natifs (+ DocTypes DTP marqués `custom` à confirmer VPS). |
|
||||
| 8 | VPS pour tous projets | Application des fixtures = VPS (§7), jamais local. |
|
||||
| — | Séparation des pouvoirs | `set_user_permissions` réservé au RBAC Admin (test). |
|
||||
|
||||
**DocTypes `custom: true`** (`Faisabilité`, `Publiciste Log`, `CONFOTUR
|
||||
Application`, `API Access`) = DocTypes DTP **à créer** — existence **à confirmer
|
||||
VPS** par l'agent ERPNext avant application (cohérent avec l'interdit « documenter
|
||||
du code sans vérifier l'existence courante »).
|
||||
|
||||
## 7. Application sur VPS (hors périmètre worker)
|
||||
|
||||
Ce worker n'écrit **jamais** sur le VPS. L'agent ERPNext Backend appliquera la
|
||||
cible côté serveur (`erpnext-backend-1`) :
|
||||
|
||||
1. Générer les fixtures `Role` + `Custom DocPerm` depuis `rbac_50_roles.json`.
|
||||
2. `bench --site frontend migrate` pour installer les rôles.
|
||||
3. Créer les DocTypes DTP `custom` manquants (§6) **après** confirmation.
|
||||
4. Mapper les `scope_donnees` en `User Permission` par utilisateur.
|
||||
5. Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big.
|
||||
|
||||
> Un **générateur de fixtures** `rbac_50_roles.json → fixtures/` est le prochain
|
||||
> incrément (branchable sur le même patron que le Publiciste) ; il reste autorable
|
||||
> en-repo sans toucher au VPS.
|
||||
|
||||
## 8. Vérification (en-repo, sans toucher au VPS)
|
||||
|
||||
- `python3 -m unittest discover -s tests -v` → **10/10 verts** (schéma maison +
|
||||
oracle `jsonschema`, 50 rôles, unicité, couverture 5 portails, séparation des
|
||||
pouvoirs).
|
||||
- `rbac_50_roles.json` : JSON strict valide (couvert par `ci/validate_json.sh`).
|
||||
- Job CI dédié `rbac-tests` ajouté au **gate** (`.gitea/workflows/ci.yml`,
|
||||
Gitea Actions uniquement · #2).
|
||||
|
||||
## 9. Auto-score 4Big du livrable : **95/100**
|
||||
|
||||
_Réserve −5_ : application des fixtures + création des DocTypes `custom` +
|
||||
mapping `User Permission` = côté VPS (agent ERPNext, hors périmètre worker) ;
|
||||
plafonds d'approbation monétaires par rôle volontairement **non chiffrés** ici
|
||||
(anti-invention #6 — à définir avec la Direction sur pièces). Validé statiquement
|
||||
en-repo (10 tests verts + schéma conforme + gate CI).
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://oto.dtp/schemas/rbac/rbac.schema.json",
|
||||
"title": "Contrat RBAC · OTO Enterprise OS DTP (50 rôles)",
|
||||
"description": "Design machine-lisible des 50 rôles RBAC (CLAUDE.md · roadmap Sprint 2 · ERPNext Backend). Chaque rôle cible un Role natif Frappe v15 + un jeu de permissions par DocType. Les bindings sont la CIBLE à appliquer sur le VPS par l'agent ERPNext (bench/fixtures) — ce document ne touche jamais la prod (contrainte worker).",
|
||||
"type": "object",
|
||||
"required": ["version", "generated_at", "cible_rbac_roles", "portails_business", "roles"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
||||
"generated_at": { "type": "string", "format": "date-time" },
|
||||
"cible_rbac_roles": {
|
||||
"type": "integer",
|
||||
"const": 50,
|
||||
"description": "Cible non-négociable CLAUDE.md « RBAC 50 rôles ». La longueur de roles[] DOIT valoir 50 (contrôlé par le test)."
|
||||
},
|
||||
"portails_business": {
|
||||
"type": "array",
|
||||
"minItems": 5,
|
||||
"maxItems": 5,
|
||||
"uniqueItems": true,
|
||||
"items": { "type": "string", "enum": ["ventes", "construction", "achat", "compta", "direction"] },
|
||||
"description": "Les 5 portails rôle métier de la roadmap Sprint 4. « plateforme » est une console technique transversale, hors de ce compte de 5."
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"minItems": 50,
|
||||
"maxItems": 50,
|
||||
"items": { "$ref": "#/definitions/role" }
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"role": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id", "nom_fr", "famille", "portail", "entite_principale",
|
||||
"niveau", "erpnext_role_name", "scope_donnees", "description",
|
||||
"modules", "permissions_cibles"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
|
||||
"minLength": 3,
|
||||
"description": "Identifiant kebab-case unique (unicité vérifiée par le test)."
|
||||
},
|
||||
"nom_fr": { "type": "string", "minLength": 1 },
|
||||
"famille": {
|
||||
"type": "string",
|
||||
"enum": ["direction", "ventes", "marketing", "construction", "achat", "finance", "faisabilite", "legal", "plateforme"]
|
||||
},
|
||||
"portail": {
|
||||
"type": "string",
|
||||
"enum": ["ventes", "construction", "achat", "compta", "direction", "plateforme"],
|
||||
"description": "Console de rattachement. Les 5 premières = portails métier (roadmap S4) ; « plateforme » = console technique transversale."
|
||||
},
|
||||
"entite_principale": {
|
||||
"type": "string",
|
||||
"enum": ["WAF", "WAG", "WA SRL", "AC Arias Cuevas", "Consortium ECR DR", "Helios RD", "Ploutos", "9060 QC", "Groupe"],
|
||||
"description": "Entité juridique de rattachement principal (CLAUDE.md §Entités). « Groupe » = périmètre consolidé transversal."
|
||||
},
|
||||
"niveau": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 5,
|
||||
"description": "Niveau hiérarchique/sensibilité : 1 externe/opérationnel → 5 direction/système."
|
||||
},
|
||||
"erpnext_role_name": {
|
||||
"type": "string",
|
||||
"minLength": 4,
|
||||
"pattern": "^OTO ",
|
||||
"description": "Nom du DocType Role Frappe v15 à créer (préfixe « OTO » pour ne pas entrer en collision avec les rôles natifs). Unicité vérifiée par le test."
|
||||
},
|
||||
"scope_donnees": {
|
||||
"type": "string",
|
||||
"enum": ["own", "equipe", "entite", "groupe"],
|
||||
"description": "Row-level (User Permissions Frappe) : own=ses docs · equipe=son équipe · entite=sa Company · groupe=consolidé."
|
||||
},
|
||||
"description": { "type": "string", "minLength": 1 },
|
||||
"modules": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": { "type": "string", "minLength": 1 },
|
||||
"description": "Modules/Workspaces ERPNext visibles pour ce rôle."
|
||||
},
|
||||
"permissions_cibles": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "Bindings CIBLES par DocType (à appliquer sur VPS via fixtures). Verbes = actions de permission Frappe v15.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["doctype", "actions"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"doctype": { "type": "string", "minLength": 1 },
|
||||
"custom": {
|
||||
"type": "boolean",
|
||||
"description": "true = DocType OTOV7/DTP à créer (non natif ERPNext) — à confirmer VPS avant application."
|
||||
},
|
||||
"actions": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"read", "write", "create", "delete", "submit", "cancel",
|
||||
"amend", "print", "email", "export", "import", "report",
|
||||
"share", "set_user_permissions"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,832 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"generated_at": "2026-07-30T00:00:00Z",
|
||||
"cible_rbac_roles": 50,
|
||||
"portails_business": ["ventes", "construction", "achat", "compta", "direction"],
|
||||
"roles": [
|
||||
{
|
||||
"id": "direction-president-waf",
|
||||
"nom_fr": "Président · WAF (Holding)",
|
||||
"famille": "direction",
|
||||
"portail": "direction",
|
||||
"entite_principale": "WAF",
|
||||
"niveau": 5,
|
||||
"erpnext_role_name": "OTO Direction Président",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Vue consolidée toutes entités ; approbations stratégiques et plafonds haut niveau. Lecture large, écriture limitée aux validations.",
|
||||
"modules": ["Accounts", "CRM", "Selling", "Buying", "Projects", "OTOV7 Faisabilité"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "report", "print", "export"] },
|
||||
{ "doctype": "Purchase Invoice", "actions": ["read", "report", "export"] },
|
||||
{ "doctype": "Opportunity", "actions": ["read", "report"] },
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "direction-dg",
|
||||
"nom_fr": "Directeur Général",
|
||||
"famille": "direction",
|
||||
"portail": "direction",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 5,
|
||||
"erpnext_role_name": "OTO Direction Générale",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Pilotage opérationnel du groupe ; approbation devis/commandes au-delà des plafonds directeurs.",
|
||||
"modules": ["Accounts", "CRM", "Selling", "Buying", "Projects", "HR"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Quotation", "actions": ["read", "write", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Sales Order", "actions": ["read", "write", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Purchase Order", "actions": ["read", "write", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Project", "actions": ["read", "write", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "direction-cfo",
|
||||
"nom_fr": "Directeur Financier (CFO)",
|
||||
"famille": "finance",
|
||||
"portail": "direction",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 5,
|
||||
"erpnext_role_name": "OTO Direction Financière",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Responsable comptabilité/trésorerie consolidées ; validation des écritures et des paiements.",
|
||||
"modules": ["Accounts", "Buying", "Selling", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Journal Entry", "actions": ["read", "write", "create", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Payment Entry", "actions": ["read", "write", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "write", "submit", "cancel", "report", "export"] },
|
||||
{ "doctype": "Purchase Invoice", "actions": ["read", "write", "submit", "cancel", "report", "export"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "direction-coo",
|
||||
"nom_fr": "Directeur des Opérations (COO)",
|
||||
"famille": "direction",
|
||||
"portail": "direction",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Direction Opérations",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Coordination construction/achat/logistique multi-projets ; supervision des jalons.",
|
||||
"modules": ["Projects", "Buying", "Stock", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Project", "actions": ["read", "write", "create", "report"] },
|
||||
{ "doctype": "Task", "actions": ["read", "write", "create", "report"] },
|
||||
{ "doctype": "Purchase Order", "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "direction-cco",
|
||||
"nom_fr": "Directeur Commercial (CCO)",
|
||||
"famille": "direction",
|
||||
"portail": "direction",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Direction Commerciale",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Stratégie commerciale groupe ; supervision pipeline et marketing.",
|
||||
"modules": ["CRM", "Selling", "Website", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Opportunity", "actions": ["read", "write", "report", "export"] },
|
||||
{ "doctype": "Quotation", "actions": ["read", "write", "report"] },
|
||||
{ "doctype": "Lead", "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "direction-board",
|
||||
"nom_fr": "Conseil d'Administration (lecture consolidée)",
|
||||
"famille": "direction",
|
||||
"portail": "direction",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 5,
|
||||
"erpnext_role_name": "OTO Conseil Administration",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Accès strictement lecture aux tableaux de bord consolidés et rapports 4Big (aucune écriture).",
|
||||
"modules": ["Accounts", "Report", "OTOV7 Faisabilité"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "report"] },
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "ventes-directeur",
|
||||
"nom_fr": "Directeur des Ventes",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Ventes Directeur",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Pilote le pipeline Helios RD ; approuve devis et remises ; assigne les leads aux équipes.",
|
||||
"modules": ["CRM", "Selling", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Lead", "actions": ["read", "write", "create", "share", "report"] },
|
||||
{ "doctype": "Opportunity", "actions": ["read", "write", "create", "report", "export"] },
|
||||
{ "doctype": "Quotation", "actions": ["read", "write", "create", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Sales Order", "actions": ["read", "write", "submit", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-chef-equipe",
|
||||
"nom_fr": "Chef d'Équipe Ventes",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Ventes Chef Équipe",
|
||||
"scope_donnees": "equipe",
|
||||
"description": "Supervise les conseillers de son équipe ; réaffecte leads et suit les objectifs.",
|
||||
"modules": ["CRM", "Selling"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Lead", "actions": ["read", "write", "create", "report"] },
|
||||
{ "doctype": "Opportunity", "actions": ["read", "write", "create", "report"] },
|
||||
{ "doctype": "Quotation", "actions": ["read", "write", "create", "submit"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-conseiller",
|
||||
"nom_fr": "Conseiller Ventes",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Ventes Conseiller",
|
||||
"scope_donnees": "own",
|
||||
"description": "Gère ses propres leads/opportunités et produit des devis (soumis à approbation).",
|
||||
"modules": ["CRM", "Selling"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Lead", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Opportunity", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Quotation", "actions": ["read", "write", "create", "print", "email"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-courtier-externe",
|
||||
"nom_fr": "Agent Externe / Courtier",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 1,
|
||||
"erpnext_role_name": "OTO Ventes Courtier Externe",
|
||||
"scope_donnees": "own",
|
||||
"description": "Partenaire externe : soumet des leads et suit ses propres réservations/commissions, sans accès aux données internes.",
|
||||
"modules": ["CRM"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Lead", "actions": ["read", "create"] },
|
||||
{ "doctype": "Opportunity", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-reservations",
|
||||
"nom_fr": "Coordinateur Réservations",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Ventes Réservations",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Enregistre les réservations/dépôts, gère la disponibilité des unités et l'agenda des visites.",
|
||||
"modules": ["Selling", "CRM"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Sales Order", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Payment Entry", "actions": ["read", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-contrats",
|
||||
"nom_fr": "Gestionnaire Contrats de Vente",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Ventes Contrats",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Établit et suit les contrats (promesse → contrat définitif) ; assure la cohérence avec le devis validé.",
|
||||
"modules": ["Selling", "Accounts"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Sales Order", "actions": ["read", "write", "submit", "print", "email"] },
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "create", "print"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-confotur",
|
||||
"nom_fr": "Coordinateur CONFOTUR (Ventes)",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Ventes CONFOTUR",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Monte les dossiers d'incitation CONFOTUR côté vente (pièces client, éligibilité) ; liaison avec l'agent ONAPI/Legal.",
|
||||
"modules": ["Selling", "OTOV7 CONFOTUR"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "CONFOTUR Application", "custom": true, "actions": ["read", "write", "create", "print"] },
|
||||
{ "doctype": "Customer", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ventes-apres-vente",
|
||||
"nom_fr": "Support Après-Vente",
|
||||
"famille": "ventes",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Ventes Après-Vente",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Traite les demandes clients post-signature (livraison, garanties) via les tickets et les tâches.",
|
||||
"modules": ["CRM", "Support", "Projects"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Issue", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Customer", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "marketing-directeur",
|
||||
"nom_fr": "Directeur Marketing",
|
||||
"famille": "marketing",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Marketing Directeur",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Pilote la marque publique Helios RD, les campagnes et la validation du contenu du site vente.otov7.com.",
|
||||
"modules": ["CRM", "Website", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Web Page", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Publiciste Log", "custom": true, "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "marketing-publiciste",
|
||||
"nom_fr": "Éditeur Contenu / Publiciste",
|
||||
"famille": "marketing",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Marketing Publiciste",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Compte applicatif de l'agent Publiciste : publie le site public à partir des faisabilités validées (jamais d'invention de prix — CLAUDE.md #6).",
|
||||
"modules": ["Website", "OTOV7 Publiciste"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Web Page", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Publiciste Log", "custom": true, "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "marketing-seo",
|
||||
"nom_fr": "Spécialiste SEO",
|
||||
"famille": "marketing",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Marketing SEO",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Optimise l'indexation trilingue FR/EN/ES (hreflang, schema.org) ; suit Google Search Console.",
|
||||
"modules": ["Website", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Web Page", "actions": ["read", "write"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "marketing-social",
|
||||
"nom_fr": "Community / Réseaux Sociaux",
|
||||
"famille": "marketing",
|
||||
"portail": "ventes",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 1,
|
||||
"erpnext_role_name": "OTO Marketing Social",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Gère les publications réseaux sociaux et remonte les leads sociaux dans le CRM.",
|
||||
"modules": ["CRM", "Website"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Lead", "actions": ["read", "create"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "construction-directeur",
|
||||
"nom_fr": "Directeur Construction",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Construction Directeur",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Dirige AC Arias Cuevas ; approuve les projets, budgets travaux et jalons de chantier.",
|
||||
"modules": ["Projects", "Buying", "Stock", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Project", "actions": ["read", "write", "create", "submit", "report"] },
|
||||
{ "doctype": "Task", "actions": ["read", "write", "create", "report"] },
|
||||
{ "doctype": "Purchase Order", "actions": ["read", "write", "submit"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "construction-chef-projet",
|
||||
"nom_fr": "Chef de Projet Construction",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Construction Chef Projet",
|
||||
"scope_donnees": "equipe",
|
||||
"description": "Pilote un projet : planning, tâches, avancement et demandes d'achat de chantier.",
|
||||
"modules": ["Projects", "Buying"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Project", "actions": ["read", "write", "report"] },
|
||||
{ "doctype": "Task", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Material Request", "actions": ["read", "write", "create", "submit"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "construction-ingenieur",
|
||||
"nom_fr": "Ingénieur de Chantier",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Construction Ingénieur",
|
||||
"scope_donnees": "equipe",
|
||||
"description": "Suit l'exécution technique sur site ; met à jour l'avancement des tâches et les feuilles de temps.",
|
||||
"modules": ["Projects"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Task", "actions": ["read", "write"] },
|
||||
{ "doctype": "Timesheet", "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "construction-architecte",
|
||||
"nom_fr": "Architecte",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Construction Architecte",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Produit le volet Architecture des faisabilités ; valide les plans et les modèles IFC.",
|
||||
"modules": ["Projects", "OTOV7 Faisabilité"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Project", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "construction-qaqc",
|
||||
"nom_fr": "Contrôleur Qualité Chantier (QA/QC)",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Construction QAQC",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Contrôle la conformité qualité du chantier ; consigne inspections et non-conformités.",
|
||||
"modules": ["Projects", "Quality"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Quality Inspection", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Task", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "construction-bim",
|
||||
"nom_fr": "Coordinateur BIM",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Construction BIM",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Coordonne les maquettes BIM (Blender/Bonsai/IFC/Speckle) ; publie les modèles vers bim-cloud.otov7.com.",
|
||||
"modules": ["Projects", "OTOV7 Faisabilité"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "write"] },
|
||||
{ "doctype": "File", "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "construction-sous-traitants",
|
||||
"nom_fr": "Superviseur Sous-traitants",
|
||||
"famille": "construction",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Construction Sous-traitants",
|
||||
"scope_donnees": "equipe",
|
||||
"description": "Suit les sous-traitants et leurs livrables ; valide l'avancement pour paiement.",
|
||||
"modules": ["Projects", "Buying"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Purchase Order", "actions": ["read", "report"] },
|
||||
{ "doctype": "Task", "actions": ["read", "write"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "achat-directeur",
|
||||
"nom_fr": "Directeur des Achats",
|
||||
"famille": "achat",
|
||||
"portail": "achat",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Achat Directeur",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Pilote la fonction achats ; approuve commandes fournisseurs au-delà des plafonds acheteurs.",
|
||||
"modules": ["Buying", "Stock", "Accounts", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Purchase Order", "actions": ["read", "write", "create", "submit", "cancel", "report"] },
|
||||
{ "doctype": "Supplier", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Material Request", "actions": ["read", "write", "submit"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "achat-acheteur",
|
||||
"nom_fr": "Acheteur / Approvisionneur",
|
||||
"famille": "achat",
|
||||
"portail": "achat",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Achat Acheteur",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Émet demandes de prix et commandes fournisseurs (soumises à approbation) ; suit les délais.",
|
||||
"modules": ["Buying", "Stock"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Material Request", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Request for Quotation", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Purchase Order", "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "achat-fournisseurs",
|
||||
"nom_fr": "Gestionnaire Fournisseurs",
|
||||
"famille": "achat",
|
||||
"portail": "achat",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Achat Fournisseurs",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Tient à jour la base fournisseurs, les conditions et la conformité documentaire.",
|
||||
"modules": ["Buying"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Supplier", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Contact", "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "achat-magasinier",
|
||||
"nom_fr": "Magasinier / Inventaire",
|
||||
"famille": "achat",
|
||||
"portail": "achat",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Achat Magasinier",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Gère les stocks de chantier/dépôt : entrées, sorties et inventaires.",
|
||||
"modules": ["Stock"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Stock Entry", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Item", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "achat-reception",
|
||||
"nom_fr": "Contrôleur Réception Matériaux",
|
||||
"famille": "achat",
|
||||
"portail": "achat",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Achat Réception",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Réceptionne et contrôle les livraisons ; établit les bons de réception.",
|
||||
"modules": ["Stock", "Buying"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Purchase Receipt", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Purchase Order", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "compta-controleur-gestion",
|
||||
"nom_fr": "Contrôleur de Gestion",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Compta Contrôle Gestion",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Suit budgets, marges et point d'équilibre (52% pré-vente) ; produit les rapports de gestion consolidés.",
|
||||
"modules": ["Accounts", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Budget", "actions": ["read", "write", "create", "report"] },
|
||||
{ "doctype": "GL Entry", "actions": ["read", "report", "export"] },
|
||||
{ "doctype": "Cost Center", "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-comptable-general",
|
||||
"nom_fr": "Comptable Général",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Compta Général",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Tient la comptabilité générale de l'entité ; saisit et rapproche les écritures.",
|
||||
"modules": ["Accounts"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Journal Entry", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Account", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-fournisseurs-ap",
|
||||
"nom_fr": "Comptable Fournisseurs (AP)",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Compta Fournisseurs AP",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Traite les factures fournisseurs et prépare les paiements (soumis à approbation trésorier/CFO).",
|
||||
"modules": ["Accounts", "Buying"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Purchase Invoice", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Payment Entry", "actions": ["read", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-clients-ar",
|
||||
"nom_fr": "Comptable Clients (AR)",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "Helios RD",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Compta Clients AR",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Émet les factures clients et suit les encaissements (Cardnet · USD/DOP) et relances.",
|
||||
"modules": ["Accounts", "Selling"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Payment Entry", "actions": ["read", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-tresorier",
|
||||
"nom_fr": "Trésorier · Ploutos",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "Ploutos",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Compta Trésorier",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Gère la trésorerie et le patrimoine monétaire (Ploutos) ; valide les décaissements.",
|
||||
"modules": ["Accounts"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Payment Entry", "actions": ["read", "write", "submit", "cancel"] },
|
||||
{ "doctype": "Bank Transaction", "actions": ["read", "write", "submit"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-paie",
|
||||
"nom_fr": "Gestionnaire Paie · Consortium ECR DR",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "Consortium ECR DR",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Compta Paie",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Traite la paie (paymaster RH Consortium ECR DR) ; établit et soumet les bulletins.",
|
||||
"modules": ["Payroll", "HR"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Salary Slip", "actions": ["read", "write", "create", "submit"] },
|
||||
{ "doctype": "Employee", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-fiscaliste-ecf",
|
||||
"nom_fr": "Fiscaliste / e-CF DGII",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Compta Fiscaliste eCF",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Gère la facturation électronique e-CF (Compupar/DGII) et la conformité fiscale RD.",
|
||||
"modules": ["Accounts", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "write", "submit", "export"] },
|
||||
{ "doctype": "Purchase Invoice", "actions": ["read", "export"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "compta-audit-uaf",
|
||||
"nom_fr": "Auditeur Interne / Conformité UAF",
|
||||
"famille": "finance",
|
||||
"portail": "compta",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Compta Audit UAF",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Audit interne et conformité anti-blanchiment (UAF) ; accès lecture/rapport étendu, aucune écriture comptable.",
|
||||
"modules": ["Accounts", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "GL Entry", "actions": ["read", "report", "export"] },
|
||||
{ "doctype": "Payment Entry", "actions": ["read", "report"] },
|
||||
{ "doctype": "Sales Invoice", "actions": ["read", "report"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "faisabilite-analyste",
|
||||
"nom_fr": "Analyste Faisabilité",
|
||||
"famille": "faisabilite",
|
||||
"portail": "direction",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Faisabilité Analyste",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Produit les faisabilités 4 volets (Masterplan/Architecture/Paysage/Ingénierie) niveau 4Big ; versionne et score.",
|
||||
"modules": ["OTOV7 Faisabilité", "Projects", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "write", "create", "submit", "report"] },
|
||||
{ "doctype": "Project", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "faisabilite-rendu-3d",
|
||||
"nom_fr": "Spécialiste Rendu 3D",
|
||||
"famille": "faisabilite",
|
||||
"portail": "construction",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Faisabilité Rendu 3D",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Génère les rendus Flux liés au projet réel (❌ IA générique interdite — CLAUDE.md) ; 6 vues/projet.",
|
||||
"modules": ["OTOV7 Faisabilité"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "File", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "faisabilite-ifc-speckle",
|
||||
"nom_fr": "Gestionnaire IFC / Speckle",
|
||||
"famille": "faisabilite",
|
||||
"portail": "construction",
|
||||
"entite_principale": "WA SRL",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Faisabilité IFC Speckle",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Exporte IFC→GLB et publie les modèles sur bim-cloud.otov7.com pour le viewer console.",
|
||||
"modules": ["OTOV7 Faisabilité"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "File", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "write"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "faisabilite-economiste",
|
||||
"nom_fr": "Économiste de la Construction (métrés)",
|
||||
"famille": "faisabilite",
|
||||
"portail": "construction",
|
||||
"entite_principale": "AC Arias Cuevas",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Faisabilité Économiste",
|
||||
"scope_donnees": "entite",
|
||||
"description": "Produit métrés et quantitatifs (BIM compras) pour le volet Ingénierie ; chiffre les coûts travaux.",
|
||||
"modules": ["OTOV7 Faisabilité", "Buying", "Stock"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "write"] },
|
||||
{ "doctype": "Item", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "legal-directeur",
|
||||
"nom_fr": "Directeur Juridique",
|
||||
"famille": "legal",
|
||||
"portail": "direction",
|
||||
"entite_principale": "WAF",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Legal Directeur",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Supervise les contrats, la conformité et les dépôts légaux du groupe ; valide les documents à portée juridique.",
|
||||
"modules": ["OTOV7 CONFOTUR", "Accounts", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "CONFOTUR Application", "custom": true, "actions": ["read", "write", "submit", "report"] },
|
||||
{ "doctype": "Contract", "actions": ["read", "write", "create", "submit"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "legal-onapi",
|
||||
"nom_fr": "Agent ONAPI / Propriété Intellectuelle",
|
||||
"famille": "legal",
|
||||
"portail": "direction",
|
||||
"entite_principale": "WAF",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Legal ONAPI",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Prépare et suit les dépôts ONAPI (marques, Classes 36/37/43) et les dossiers CONFOTUR (P05/P07).",
|
||||
"modules": ["OTOV7 CONFOTUR"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "CONFOTUR Application", "custom": true, "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "plateforme-devops",
|
||||
"nom_fr": "Administrateur Système (DevOps)",
|
||||
"famille": "plateforme",
|
||||
"portail": "plateforme",
|
||||
"entite_principale": "9060 QC",
|
||||
"niveau": 5,
|
||||
"erpnext_role_name": "OTO Plateforme DevOps",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Administre l'infrastructure (Docker, Gitea, systemd, nginx) et les déploiements. Aucune plateforme git hors Gitea (CLAUDE.md #2).",
|
||||
"modules": ["Core", "Website", "Report"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Scheduled Job Type", "actions": ["read", "write"] },
|
||||
{ "doctype": "Server Script", "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plateforme-rbac-admin",
|
||||
"nom_fr": "Administrateur RBAC / Sécurité",
|
||||
"famille": "plateforme",
|
||||
"portail": "plateforme",
|
||||
"entite_principale": "9060 QC",
|
||||
"niveau": 5,
|
||||
"erpnext_role_name": "OTO Plateforme RBAC Admin",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Gère utilisateurs, rôles et User Permissions ; seul habilité à modifier les habilitations (séparation des pouvoirs).",
|
||||
"modules": ["Users and Permissions", "Core"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "User", "actions": ["read", "write", "create", "set_user_permissions"] },
|
||||
{ "doctype": "Role", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Role Profile", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "User Permission", "actions": ["read", "write", "create", "delete"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plateforme-qa",
|
||||
"nom_fr": "Ingénieur QA Plateforme",
|
||||
"famille": "plateforme",
|
||||
"portail": "plateforme",
|
||||
"entite_principale": "9060 QC",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Plateforme QA",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Exécute les audits qualité 4Big (Playwright, night-audit) ; accès lecture large + rapports, aucune écriture métier.",
|
||||
"modules": ["Report", "Core"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Report", "actions": ["read", "report", "export"] },
|
||||
{ "doctype": "Error Log", "actions": ["read"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plateforme-otoia",
|
||||
"nom_fr": "Orchestrateur OTOIA (compte système)",
|
||||
"famille": "plateforme",
|
||||
"portail": "plateforme",
|
||||
"entite_principale": "9060 QC",
|
||||
"niveau": 4,
|
||||
"erpnext_role_name": "OTO Plateforme OTOIA",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Compte de service de l'agent OTOIA (AEC + RAG + prompt engine). Écrit faisabilités et logs via API ; périmètre limité aux DocTypes DTP.",
|
||||
"modules": ["OTOV7 Faisabilité", "OTOV7 Publiciste", "Core"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Faisabilité", "custom": true, "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Publiciste Log", "custom": true, "actions": ["read", "write", "create"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plateforme-mobile",
|
||||
"nom_fr": "Développeur Mobile",
|
||||
"famille": "plateforme",
|
||||
"portail": "plateforme",
|
||||
"entite_principale": "9060 QC",
|
||||
"niveau": 2,
|
||||
"erpnext_role_name": "OTO Plateforme Mobile",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Maintient l'app Expo/React Native et l'API mobile ; gère les builds EAS et les soumissions stores.",
|
||||
"modules": ["Core", "Website"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "API Access", "custom": true, "actions": ["read", "write"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plateforme-bi",
|
||||
"nom_fr": "Analyste Données / BI",
|
||||
"famille": "plateforme",
|
||||
"portail": "plateforme",
|
||||
"entite_principale": "Groupe",
|
||||
"niveau": 3,
|
||||
"erpnext_role_name": "OTO Plateforme BI",
|
||||
"scope_donnees": "groupe",
|
||||
"description": "Construit tableaux de bord et rapports consolidés (lecture seule) pour la direction ; aucune écriture transactionnelle.",
|
||||
"modules": ["Report", "Accounts", "CRM"],
|
||||
"permissions_cibles": [
|
||||
{ "doctype": "Dashboard", "actions": ["read", "write", "create"] },
|
||||
{ "doctype": "Report", "actions": ["read", "write", "create", "export"] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
"""Tests RBAC 50 rôles — stdlib pur (unittest), zéro dépendance pip.
|
||||
|
||||
Réutilise le validateur JSON-Schema du module Publiciste (Sprint 2) plutôt que
|
||||
d'en dupliquer un (CLAUDE.md · workflow #5 « éliminer le vieux / ne pas
|
||||
accumuler de doublons »). L'oracle `jsonschema` est utilisé s'il est présent.
|
||||
|
||||
Invariants vérifiés :
|
||||
1. `rbac_50_roles.json` valide contre `rbac.schema.json`.
|
||||
2. EXACTEMENT 50 rôles (cible non-négociable CLAUDE.md « RBAC 50 rôles »).
|
||||
3. `id` et `erpnext_role_name` uniques (pas de collision de rôle Frappe).
|
||||
4. Les 5 portails métier de la roadmap S4 sont tous couverts par ≥1 rôle.
|
||||
5. Cohérence interne (portail déclaré ⊆ portails connus, cible=50).
|
||||
6. Anti-invention (#6) : aucun rôle « own/equipe » n'a le pouvoir
|
||||
`set_user_permissions` (élévation de privilège) — réservé au RBAC Admin.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import unittest
|
||||
|
||||
# --- localisation des fichiers -------------------------------------------------
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
RBAC_DIR = os.path.dirname(HERE)
|
||||
DELIVERABLES = os.path.dirname(RBAC_DIR)
|
||||
|
||||
DATA_PATH = os.path.join(RBAC_DIR, "rbac_50_roles.json")
|
||||
SCHEMA_PATH = os.path.join(RBAC_DIR, "rbac.schema.json")
|
||||
|
||||
# --- réutilisation du validateur Publiciste (pas de duplication) ---------------
|
||||
import sys
|
||||
sys.path.insert(0, os.path.join(DELIVERABLES, "publiciste"))
|
||||
from lib import validator as maison # noqa: E402
|
||||
|
||||
|
||||
def _load(path):
|
||||
with open(path, encoding="utf-8") as fh:
|
||||
return json.load(fh)
|
||||
|
||||
|
||||
class RbacContractTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.data = _load(DATA_PATH)
|
||||
cls.schema = _load(SCHEMA_PATH)
|
||||
cls.roles = cls.data["roles"]
|
||||
|
||||
# 1 · conformité au schéma (validateur maison)
|
||||
def test_valide_contre_schema_maison(self):
|
||||
errors = maison.validate(self.data, self.schema)
|
||||
self.assertEqual(errors, [], f"Erreurs de schéma (maison) : {errors}")
|
||||
|
||||
# 1bis · oracle jsonschema si disponible
|
||||
def test_valide_contre_oracle_jsonschema_si_present(self):
|
||||
try:
|
||||
import jsonschema
|
||||
except ImportError:
|
||||
self.skipTest("jsonschema non installé (validateur maison fait foi)")
|
||||
jsonschema.validate(self.data, self.schema)
|
||||
|
||||
# 2 · cible non-négociable = 50
|
||||
def test_exactement_50_roles(self):
|
||||
self.assertEqual(self.data["cible_rbac_roles"], 50)
|
||||
self.assertEqual(len(self.roles), 50, "La cible CLAUDE.md « RBAC 50 rôles » exige exactement 50 rôles.")
|
||||
|
||||
# 3 · unicité des identifiants et des noms de rôle Frappe
|
||||
def test_ids_uniques(self):
|
||||
ids = [r["id"] for r in self.roles]
|
||||
self.assertEqual(len(ids), len(set(ids)), "id de rôle dupliqué.")
|
||||
|
||||
def test_noms_erpnext_uniques(self):
|
||||
names = [r["erpnext_role_name"] for r in self.roles]
|
||||
self.assertEqual(len(names), len(set(names)), "erpnext_role_name dupliqué (collision Frappe).")
|
||||
|
||||
def test_noms_erpnext_prefixes_oto(self):
|
||||
for r in self.roles:
|
||||
self.assertTrue(
|
||||
r["erpnext_role_name"].startswith("OTO "),
|
||||
f"{r['id']}: le rôle Frappe doit être préfixé « OTO » pour éviter la collision avec les rôles natifs.",
|
||||
)
|
||||
|
||||
# 4 · les 5 portails métier de la roadmap S4 sont tous couverts
|
||||
def test_cinq_portails_business_couverts(self):
|
||||
portails_declares = set(self.data["portails_business"])
|
||||
self.assertEqual(portails_declares, {"ventes", "construction", "achat", "compta", "direction"})
|
||||
portails_utilises = {r["portail"] for r in self.roles}
|
||||
for p in portails_declares:
|
||||
self.assertIn(p, portails_utilises, f"Portail métier « {p} » sans aucun rôle rattaché.")
|
||||
|
||||
# 5 · cohérence portail
|
||||
def test_portail_connu(self):
|
||||
connus = {"ventes", "construction", "achat", "compta", "direction", "plateforme"}
|
||||
for r in self.roles:
|
||||
self.assertIn(r["portail"], connus, f"{r['id']}: portail inconnu {r['portail']!r}")
|
||||
|
||||
# 6 · anti-élévation de privilège : set_user_permissions réservé au groupe
|
||||
def test_set_user_permissions_reserve_admin(self):
|
||||
for r in self.roles:
|
||||
verbs = {a for p in r["permissions_cibles"] for a in p["actions"]}
|
||||
if "set_user_permissions" in verbs:
|
||||
self.assertEqual(
|
||||
r["scope_donnees"], "groupe",
|
||||
f"{r['id']}: 'set_user_permissions' exige un scope 'groupe' (séparation des pouvoirs).",
|
||||
)
|
||||
self.assertEqual(
|
||||
r["famille"], "plateforme",
|
||||
f"{r['id']}: seul un rôle 'plateforme' peut porter 'set_user_permissions'.",
|
||||
)
|
||||
|
||||
# 7 · chaque rôle a au moins un binding de permission
|
||||
def test_chaque_role_a_des_permissions(self):
|
||||
for r in self.roles:
|
||||
self.assertGreaterEqual(len(r["permissions_cibles"]), 1, f"{r['id']}: aucun binding de permission.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user