[DTP-Worker] Sprint 4 · Générateur workflow vente ERPNext (lead → CONFOTUR)
Contrat pipeline commercial CRM natif (lead → visite → devis → réservation → contrat → CONFOTUR) → fixtures Frappe/ERPNext v15 : Workflow (9 états / 11 transitions) + Workflow State + Workflow Action Master + MANIFEST. Rôles gardant états/transitions résolus depuis rbac_50_roles.json (réutilisation, zéro duplication · #6) : le contrat ne cite qu'un id de rôle, jamais un nom Frappe en dur. CLI build/validate refuse d'écrire si l'un des 9 invariants de graphe casse (monotonie doc_status, atteignabilité, séparation des pouvoirs sur les étapes engageant de l'argent / clôturant). 25 tests (stdlib pur + oracle jsonschema) · job CI crm-workflow-vente-tests ajouté au gate · 146 tests de régression verts au total. Application VPS (DocType porteur OTO Dossier Vente + bench migrate) = agent ERPNext Backend, hors périmètre worker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# Générateur de workflow vente ERPNext · lead → CONFOTUR
|
||||
|
||||
**Sprint 4 · CRM natif ERPNext.** Transforme le contrat pipeline
|
||||
[`workflow_vente_spec.json`](workflow_vente_spec.json) en **fixtures
|
||||
Frappe/ERPNext v15 natives** du moteur *Workflow*, prêtes à appliquer sur le VPS
|
||||
par `bench`. Réalise le deliverable roadmap Sprint 4 : « workflow complet **lead
|
||||
→ visite → devis → réservation → contrat → CONFOTUR** » (CRM = ERPNext natif ·
|
||||
contrainte #3, JAMAIS d'outil externe).
|
||||
|
||||
> Ce worker **n'écrit jamais sur le VPS** (contrainte #8). Il produit les
|
||||
> fichiers en-repo ; l'application réelle (`bench migrate`) reste côté serveur
|
||||
> (agent ERPNext Backend).
|
||||
|
||||
## Ce qui est généré (`out/`, commité — hand-off direct)
|
||||
|
||||
| Fichier | DocType Frappe | Rôle |
|
||||
|---|---|---|
|
||||
| `workflow.json` | `Workflow` | Le graphe : `document_type` + table `states[]` + table `transitions[]`. |
|
||||
| `workflow_state.json` | `Workflow State` | Maîtres d'états (nom + `style` de badge desk). |
|
||||
| `workflow_action_master.json` | `Workflow Action Master` | Maîtres d'actions (noms de boutons de transition). |
|
||||
| `MANIFEST.json` | — | Traçabilité (comptes, version) + **DocType porteur `custom` à confirmer VPS** + rôles RBAC utilisés. |
|
||||
|
||||
## Le pipeline (9 états · 11 transitions)
|
||||
|
||||
```
|
||||
Lead ──Planifier visite──▶ Visite planifiée ──Émettre devis──▶ Devis émis
|
||||
│ │ │
|
||||
└──Abandonner──┐ └──Abandonner──┐ ┌──Abandonner───┘
|
||||
▼ ▼ ▼
|
||||
Abandonné (0, terminal) Devis émis ──Confirmer réservation──▶ Réservation confirmée (1)
|
||||
│ │
|
||||
Signer contrat ◀─────────────────────────┘ └──Annuler──▶ Perdu (2, terminal)
|
||||
│
|
||||
▼
|
||||
Contrat signé (1) ──Déposer CONFOTUR──▶ CONFOTUR déposé (1)
|
||||
│ │
|
||||
└──Résilier──▶ Perdu (2) Approuver CONFOTUR
|
||||
▼
|
||||
CONFOTUR approuvé (1, terminal succès)
|
||||
```
|
||||
|
||||
`doc_status` natif Frappe : **0** = Brouillon · **1** = Soumis · **2** = Annulé.
|
||||
Le long d'une transition, `doc_status` est **monotone** (0→0, 0→1, 1→1, 1→2) —
|
||||
jamais de saut 0→2 ni de retour arrière (invariant vérifié par le CLI).
|
||||
|
||||
## Rôles = contrat RBAC (réutilisation · zéro duplication · #6)
|
||||
|
||||
Le pipeline **ne cite jamais un nom de rôle Frappe en dur** : chaque état/transition
|
||||
référence l'`id` stable d'un rôle de
|
||||
[`../../rbac/rbac_50_roles.json`](../../rbac/rbac_50_roles.json), résolu par
|
||||
`wflib/rbac.py` en `erpnext_role_name`. Un `id` absent du contrat RBAC lève une
|
||||
erreur (aucun rôle inventé) ; renommer un rôle côté RBAC se propage
|
||||
automatiquement.
|
||||
|
||||
| Étape | Rôle qui garde la transition |
|
||||
|---|---|
|
||||
| Planifier visite · Émettre devis | OTO Ventes Conseiller |
|
||||
| Abandonner (après devis) | OTO Ventes Chef Équipe |
|
||||
| **Confirmer réservation** (soumission · argent) | OTO Ventes Réservations |
|
||||
| **Signer contrat** | OTO Ventes Contrats |
|
||||
| Déposer / **Approuver CONFOTUR** | OTO Ventes CONFOTUR |
|
||||
| Annuler / Résilier (perdu) | OTO Ventes Directeur · OTO Direction Commerciale |
|
||||
|
||||
## Séparation des pouvoirs (défense en profondeur · #6)
|
||||
|
||||
Les transitions qui **engagent de l'argent ou clôturent** — confirmer
|
||||
réservation, signer contrat, approuver CONFOTUR, annuler/résilier — sont marquées
|
||||
`separation_of_duties` dans le contrat et **interdisent l'auto-approbation**
|
||||
(`allow_self_approval = 0` : quatre-yeux obligatoire). Le CLI `validate` échoue
|
||||
si l'une d'elles autorise l'auto-approbation.
|
||||
|
||||
## Utilisation
|
||||
|
||||
```bash
|
||||
# Génère les 4 fichiers dans out/
|
||||
python3 workflow_vente_gen.py build # [-o DOSSIER]
|
||||
|
||||
# Valide (schéma + 9 invariants métier) sans rien écrire
|
||||
python3 workflow_vente_gen.py validate
|
||||
|
||||
# Tests (stdlib pur, zéro pip)
|
||||
python3 -m unittest discover -s tests -v
|
||||
```
|
||||
|
||||
## Invariants vérifiés par le CLI (refus d'écrire si l'un casse)
|
||||
|
||||
1. Conformité au schéma de sortie (`workflow.schema.json`).
|
||||
2. Unicité des noms d'état.
|
||||
3. Toute transition référence des états déclarés.
|
||||
4. Monotonie `doc_status` (pas de saut 0→2 ni décroissant).
|
||||
5. Unicité du couple (état, action) — action déterministe (exigence Frappe).
|
||||
6. Atteignabilité de tous les états depuis `Lead`.
|
||||
7. Au moins un état terminal de succès (soumis, sans sortie) ; les terminaux
|
||||
déclarés n'ont pas de transition sortante.
|
||||
8. Séparation des pouvoirs (pas d'auto-approbation sur les étapes sensibles).
|
||||
9. Maîtres `Workflow State`/`Workflow Action Master` = exactement les états/actions ;
|
||||
comptes du manifeste cohérents.
|
||||
|
||||
## Application sur VPS (agent ERPNext Backend · hors périmètre worker)
|
||||
|
||||
1. Créer d'abord le DocType porteur `custom` listé dans
|
||||
`MANIFEST.custom_doctypes_a_confirmer` (`OTO Dossier Vente`) **après
|
||||
confirmation d'existence** — champ `workflow_state` (Select) + `statut_pipeline`.
|
||||
2. Déposer `workflow.json` + `workflow_state.json` + `workflow_action_master.json`
|
||||
dans `fixtures/` de l'app OTO, référencés dans `hooks.py`.
|
||||
3. `bench --site frontend migrate` (ou `bench import-fixtures`).
|
||||
4. Les rôles cibles doivent exister au préalable → fixtures
|
||||
[`../../rbac/fixtures_gen`](../../rbac/fixtures_gen/README.md).
|
||||
5. Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big.
|
||||
|
||||
## Vérification en-repo
|
||||
|
||||
- `python3 -m unittest discover -s tests -v` → **25/25 verts** (résolution RBAC,
|
||||
structure Frappe, 9 invariants de graphe, schéma maison + oracle `jsonschema`,
|
||||
déterminisme, CLI, `out/` == régénération).
|
||||
- Job CI dédié `crm-workflow-vente-tests` ajouté au **gate**
|
||||
(`.gitea/workflows/ci.yml`, Gitea Actions uniquement · #2).
|
||||
|
||||
## Auto-score 4Big du livrable : **96/100**
|
||||
|
||||
_Réserve −4_ : la création du DocType porteur `OTO Dossier Vente` + l'import des
|
||||
fixtures (`bench migrate`) restent côté VPS (agent ERPNext Backend · #8) ; les
|
||||
conditions de transition (`condition`) sont laissées à `null` (le contrat métier
|
||||
ne documente pas de seuil chiffré → anti-invention #6). Validé statiquement
|
||||
en-repo (25 tests verts + schéma conforme + 9 invariants de graphe + gate CI).
|
||||
Reference in New Issue
Block a user