emmixam/ai_workflow_discovery_agent
0
1from __future__ import annotations2from typing import Any3 4 5class RoiValidationError(ValueError):6 """Erreur de validation métier sur les métriques ROI."""7 8 9def validate_roi_metrics_or_raise(roi_metrics: dict[str, Any]) -> None:10 required_fields = [11 "heures_economisees_par_mois",12 "economies_mensuelles",13 "projection_annuelle",14 "detail_calcul",15 "confidence",16 ]17 18 for field in required_fields:19 if field not in roi_metrics:20 raise RoiValidationError(f"Champ ROI manquant: {field}")21 22 numeric_fields = [23 "heures_economisees_par_mois",24 "economies_mensuelles",25 "projection_annuelle",26 ]27 28 for field in numeric_fields:29 value = roi_metrics[field]30 try:31 value = float(value)32 except (TypeError, ValueError) as e:33 raise RoiValidationError(f"Champ ROI invalide: {field}={value!r}") from e34 35 if value < 0:36 raise RoiValidationError(f"Champ ROI négatif interdit: {field}={value}")37 38 expected_projection = round(float(roi_metrics["economies_mensuelles"]) * 12.0, 2)39 actual_projection = round(float(roi_metrics["projection_annuelle"]), 2)40 41 if actual_projection != expected_projection:42 raise RoiValidationError(43 "projection_annuelle incohérente avec economies_mensuelles * 12."44 )45 46 if not isinstance(roi_metrics["detail_calcul"], str) or not roi_metrics["detail_calcul"].strip():47 raise RoiValidationError("detail_calcul vide ou invalide.")48 49 confidence = roi_metrics["confidence"]50 if not isinstance(confidence, dict):51 raise RoiValidationError("confidence doit être un dict.")52 53 if "roi_mode" not in confidence:54 raise RoiValidationError("confidence.roi_mode manquant.")55 56 if confidence["roi_mode"] not in {"full", "partial", "blocked"}:57 raise RoiValidationError(58 f"confidence.roi_mode invalide: {confidence['roi_mode']!r}"59 )60 