feat: viewer — affichage qualité CPAM, traçabilité décisions DP/DAS, VetoReport et bio

- CPAM : badge quality_tier (A/B/C), bandeau requires_review, warnings catégorisés, force probante dossier
- DP/DAS : code suggestion barré → code final si modifié, ligne grisée si ruled_out, badges décision + règles
- DAS : badge needs_info avec détails, raison ruled_out sous la ligne
- VetoReport : section contestabilité avec verdict, barre score/100, tableau issues HARD/MEDIUM/LOW
- Biologie : badge Suspect avec tooltip, valeurs écartées en details pliable
- Nouveau filtre Jinja2 decision_badge, import _assess_dossier_strength (pas de duplication)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dom
2026-02-23 10:56:15 +01:00
parent cc642c1143
commit 1e79b7cc52
2 changed files with 205 additions and 8 deletions

View File

@@ -22,6 +22,7 @@ from ..config import (
CIM10_PDF, GUIDE_METHODO_PDF, CCAM_PDF, CIM10_DICT_PATH, CIM10_SUPPLEMENTS_PATH,
)
from .. import config as cfg
from ..control.cpam_context import _assess_dossier_strength
from .referentiels import ReferentielManager
from .validation import ValidationManager
@@ -374,6 +375,24 @@ def format_doc_name(name: str) -> str:
return name
def decision_badge(decision) -> Markup:
"""Badge HTML pour une CodeDecision (action != KEEP)."""
if not decision:
return Markup("")
action = decision.get("action", "KEEP") if isinstance(decision, dict) else getattr(decision, "action", "KEEP")
if action == "KEEP":
return Markup("")
labels = {
"DOWNGRADE": ("Rétrogradé", "#fef3c7", "#92400e"),
"REMOVE": ("Supprimé", "#fee2e2", "#dc2626"),
"RULED_OUT": ("Écarté", "#f1f5f9", "#64748b"),
"NEED_INFO": ("Info requise", "#fff7ed", "#c2410c"),
"PROMOTE_DP": ("Promu DP", "#dbeafe", "#1d4ed8"),
}
label, bg, fg = labels.get(action, (action, "#f1f5f9", "#64748b"))
return Markup(f'<span class="badge" style="background:{bg};color:{fg};font-size:0.7rem;">{label}</span>')
def format_cpam_text(text: str | None) -> Markup:
"""Convertit un texte CPAM (section) en HTML avec puces et paragraphes."""
if not text:
@@ -420,6 +439,7 @@ def create_app() -> Flask:
app.jinja_env.filters["format_dossier_name"] = format_dossier_name
app.jinja_env.filters["format_doc_name"] = format_doc_name
app.jinja_env.filters["format_cpam_text"] = format_cpam_text
app.jinja_env.filters["decision_badge"] = decision_badge
ccam_dict = load_ccam_dict()
@@ -440,6 +460,8 @@ def create_app() -> Flask:
if len(rel_parts) > 1:
current_group = str(Path(*rel_parts[:-1]))
siblings = groups.get(current_group, [])
# Force probante (pour section CPAM)
dossier_strength = _assess_dossier_strength(dossier) if dossier.controles_cpam else None
return render_template(
"detail.html",
dossier=dossier,
@@ -447,6 +469,7 @@ def create_app() -> Flask:
ccam_dict=ccam_dict,
siblings=siblings,
current_group=current_group,
dossier_strength=dossier_strength,
)
@app.route("/dashboard")