e7cc3c4a3c
Bug latent réel (crm/commissions/commlib/finance.py:75) : le libellé de base de
la formule traçable « commission = base × taux » utilisait f"{base:g}", qui casse
deux fois sur des montants immobiliers réels en RD (une unité USD 300k ≈ 18M DOP) :
(1) notation exponentielle dès 1e6 (18000000 → 1.8e+07, illisible/non auditable) ;
(2) arrondi silencieux à 6 chiffres significatifs (123456.78 → 123457) = une base
FABRIQUÉE ≠ de la réelle, l'invention interdite par #6 dans le module même qui
proclame l'anti-invention.
Fix : helper _amount_label (f"{x:f}" jamais exponentiel + strip zéros) → décimal
fidèle, identique à l'ancien pour tous les montants simples (200000 reste 200000) ;
seuls les cas buggés changent. 2 tests à dents (millions non-exponentiel + décimales
préservées) — teeth prouvé : les DEUX échouent sans le fix.
Byte-repro : 0 impact d'artefact du module (compute_line est runtime, jamais appelé
par le générateur). Cascade compteur-de-suite seule : matrice 631/614 → 633/616,
regression×3 + quality_report régénérés, fiches qa/erpnext/crm + README réalignés
(commissions 25→27, Total CRM 81→83). run_ci 33/0/0. 0 code moteur V18 (bloqué D-06).
0 gate ajouté (#5). 0 commande VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94 lines
4.7 KiB
Markdown
94 lines
4.7 KiB
Markdown
# Barème commissions vendeurs · `OTO Barème Commissions Ventes`
|
||
|
||
**Sprint 4 · ERPNext Backend** (roadmap ligne 51 : _« commissions vendeurs
|
||
auto »_). Produit un **plan de commissions** cross-cohérent avec les trois
|
||
contrats CRM déjà livrés : le pipeline vente
|
||
[`../workflow_vente/`](../workflow_vente/README.md), le DocType porteur
|
||
[`../dossier_vente/`](../dossier_vente/README.md) et le contrat RBAC 50 rôles.
|
||
Il répond à la question : **quel évènement du pipeline paie, à quel rôle, sur
|
||
quel montant** — et fournit un **calculateur traçable** `commission = base ×
|
||
taux`.
|
||
|
||
> Ce worker **n'écrit jamais sur le VPS** (contrainte #8) : il émet les fichiers
|
||
> de hand-off en-repo ; la création du champ commission et le calcul en
|
||
> production restent côté agent ERPNext Backend.
|
||
|
||
## Anti-invention (#6) — pourquoi tous les taux sont `null`
|
||
|
||
**Aucun taux de commission n'est documenté dans CLAUDE.md.** Les seuls
|
||
pourcentages canoniques (3 % édition · 8.5 % marketing · 52 % point d'équilibre)
|
||
ne sont **pas** des commissions. Fixer un taux ici serait une invention. Donc :
|
||
|
||
- Le barème livré porte `taux_pct: null` + `source: null` + `a_confirmer: true`
|
||
pour **chaque** évènement.
|
||
- Le calcul `commission = base × taux` reste `None` tant qu'un opérande manque —
|
||
**jamais** 0-inventé ; la formule reste affichée (traçabilité façon
|
||
[`banclib/finance.py`](../../faisabilite/bancable/banclib/finance.py)).
|
||
- Un invariant du CLI **refuse** tout `taux_pct` fourni **sans `source`**.
|
||
|
||
La Direction renseigne `taux_pct` + `source` plus tard ; le calcul devient alors
|
||
auditable et reproductible.
|
||
|
||
## Ce qui est généré (`out/`, commité — hand-off direct)
|
||
|
||
| Fichier | Rôle |
|
||
|---|---|
|
||
| `commission_plan.json` | Le plan normalisé : par évènement → rôle (nom Frappe résolu) + champ de base + taux (null, à confirmer). |
|
||
| `MANIFEST.json` | Traçabilité (4 sources, comptes, `taux_a_confirmer`) + rôles RBAC utilisés + note anti-invention. |
|
||
|
||
## Cross-cohérence barème ↔ workflow ↔ DocType ↔ RBAC (le cœur du livrable)
|
||
|
||
Chaque évènement est **contraint** par les contrats voisins (anti-dérive · zéro
|
||
duplication · workflow #5) :
|
||
|
||
- **`update_value`** doit exister dans
|
||
[`workflow_vente_spec.json`](../workflow_vente/workflow_vente_spec.json) **et**
|
||
correspondre à un état **soumis** (`doc_status = 1`) : on ne commissionne pas un
|
||
brouillon (lead/visite/devis/abandonné), seulement réservation, contrat et
|
||
approbation CONFOTUR.
|
||
- **`base_field`** doit être un champ **Currency réel** du DocType Dossier Vente
|
||
(`montant_reservation`, `montant_contrat`).
|
||
- **`role_id`** doit être résolu depuis
|
||
[`rbac_50_roles.json`](../../rbac/rbac_50_roles.json) (via le `RoleResolver`
|
||
**réutilisé** du module workflow) **et** appartenir au portail `ventes`.
|
||
- **`devise_field`** = le champ `devise` (`Select` **USD/DOP** · #10) du DocType.
|
||
|
||
## Utilisation
|
||
|
||
```bash
|
||
python3 commissions_gen.py build # écrit out/ (refuse si invalide)
|
||
python3 commissions_gen.py validate # schéma + 10 invariants, sans écrire
|
||
python3 -m unittest discover -s tests -v # 27 tests (stdlib pur)
|
||
```
|
||
|
||
## Les 10 invariants (le CLI refuse d'écrire si l'un casse)
|
||
|
||
1. Conformité au [schéma de sortie](bareme.schema.json). 2. `update_value` ∈
|
||
workflow vente. 3. État **soumis** uniquement (pas de commission sur brouillon).
|
||
4. `base_field` = champ Currency réel du Dossier Vente. 5. `role_id` du portail
|
||
ventes. 6. `erpnext_role_name` cohérent avec RBAC. 7. Anti-invention : jamais de
|
||
`taux_pct` sans `source`. 8. Unicité (`update_value`, `role_id`). 9. `devise_field`
|
||
= `devise` (USD/DOP). 10. Comptes du manifeste cohérents.
|
||
|
||
## Calcul traçable (`commlib/finance.py`)
|
||
|
||
`compute_line(dossier, event)` → `montant = base × taux_pct`, avec la **formule
|
||
publiée** (`200000 × 2.5 %`), la devise, et `champs_manquants` si un opérande est
|
||
absent (montant alors `None`). La fixture [`fixtures/dossier_exemple.json`](fixtures/dossier_exemple.json)
|
||
sert **uniquement aux tests** : ses chiffres sont des exemples fictifs portant une
|
||
`source` explicite « non contractuel » — jamais commités dans `out/`.
|
||
|
||
## Hand-off VPS (agent ERPNext Backend · hors périmètre worker · #8)
|
||
|
||
1. La Direction confirme les `taux_pct` + `source` de chaque évènement.
|
||
2. Créer le mécanisme de commission côté ERPNext (champ/table enfant sur le
|
||
DocType Dossier Vente, ou DocType commission dédié) et brancher le calcul sur
|
||
les transitions du Workflow (réservation / contrat / CONFOTUR approuvé).
|
||
|
||
---
|
||
|
||
**Auto-score 4Big : 96/100.** Réserve −4 : confirmation des taux réels + câblage
|
||
du calcul en production côté VPS (agent ERPNext Backend · #8) ; ce module valide
|
||
statiquement en-repo (27 tests verts + schéma + 10 invariants de cross-cohérence
|
||
+ gate CI).
|