Format JSON Devis — Deviseur IA EG EVENT¶
Format obligatoire pour les tools verify_arithmetic, generate_xls, archive_quote.
Structure top-level¶
{
"devis": {
"ref": "DEV-2026-XXX",
"client": "Nom du client",
"salon": "Nom du salon",
"ville": "Paris",
"surface": 30,
"type_stand": "menuiserie sur mesure",
"site_depart": "Villebon-sur-Yvette",
"date_creation": "2026-05-20",
"version": 1,
"tva_pct": 20,
"auteur_email": "olivier.audemard@gmail.com",
"postes": [
{ ... },
{ ... }
],
"sous_totaux_par_categorie": {
"Sol": 1440.00,
"Menuiserie": 4068.13,
"Mobilier": 1138.80
},
"total_ht": 21044.23,
"tva_montant": 4208.85,
"total_ttc": 25253.08,
"marge_globale": 35.5
}
}
⚠️ Clé OBLIGATOIRE : postes (pas lignes ni items ni lines)¶
La liste des lignes de devis s'appelle postes dans devis["postes"]. Tout autre nom de clé sera ignoré silencieusement par les tools (total_ht calculé = 0).
Structure d'un poste (ligne de devis)¶
{
"categorie": "Menuiserie",
"description": "Cloison double face H=2,50m finie",
"ref_produit": "CLOI-DF-250-ML",
"fournisseur": "EG EVENT",
"quantite": 11,
"unite": "ml",
"pa_ht": 65.00,
"pv_ht": 112.00,
"marge_pct": 72.3,
"total_pv_ht": 1232.00,
"source_niveau": "EXACT",
"source_ref": "[M020] Base de prix/Prix_Menuiserie_Stand.md",
"note": "",
"hypothese": "",
"flag": false
}
Champs obligatoires par poste¶
categorie(string) : Sol, Menuiserie, Mobilier, Électricité, MO, Logistique, Signalétique, etc.description(string)quantite(number)unite(string) : ml, m², u, h, j, forfait, etc.pa_ht(number) : prix achat HT unitairepv_ht(number) : prix vente HT unitairemarge_pct(number) : marge en % = (pv-pa)/pa × 100 [G003]total_pv_ht(number) : quantite × pv_ht
Champs recommandés¶
ref_produit(string) : code Odoo (10-01-001,08-01-018, etc.)fournisseur(string) : nom du fournisseur (déclenche [G007] pour les sous-traitants à 0% marge)source_niveau(string) : EXACT | CALCUL | HISTORIQUE | INCONNUsource_ref(string) : référence règle + fichier source ([M020] Base de prix/...)flag(boolean) : true si donnée manquante ou anomalie
Source de vérité du parseur¶
mcp-deviseur/tools/arithmetic.pyligne 31 :for i, p in enumerate(devis.get("postes", []))mcp-deviseur/tools/xls_generator.pyligne 88 :postes = sorted(devis.get("postes", []), ...)mcp-deviseur/tools/quote_search.py: utilisefrontmatter Obsidiansur les .md, pas ce JSON
Pièges connus¶
- ❌
"lignes"au lieu de"postes"→ total_ht calculé = 0 - ❌ Quantité en string
"30"au lieu de number30→ ignoré - ❌ Oublier
total_pv_htpar ligne → ignoré dans les sous-totaux - ❌ Mettre
marge_pctcalculée sur PV au lieu de PA → warning [G003]