Files
pointeuse-optimisator/app/classement.py
toto b6e0fcd925 Implémente système multi-utilisateurs avec classement
- Auth cookie simple (SSO-ready) : login/logout, redirection si non authentifié
- Données isolées par utilisateur dans /data/users/{user_id}/
- Migration automatique des données legacy au premier login
- Page classement avec podium et tableau comparatif (score, précision zéro, conformité)
- Nav mise à jour : Classement, affichage utilisateur courant, déconnexion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:29:07 +02:00

49 lines
1.9 KiB
Python

"""Leaderboard stats: compare all users on overtime precision and directive compliance."""
from models import list_users
from stats import compute_all_stats, _compliance_over, _day_compliant
from calcul import minutes_to_hhmm
def compute_classement() -> list[dict]:
"""Return ranked list of users with their key metrics."""
results = []
for user_id in list_users():
s = compute_all_stats(user_id)
if not s["weekly_balances"] and s["n_jours"] == 0:
continue # skip empty accounts
balances = [b["delta_min"] for b in s["weekly_balances"]]
# Precision: % of weeks where |solde| ≤ 30 min (≈ at zero)
if balances:
pct_zero = round(100 * sum(1 for b in balances if abs(b) <= 30) / len(balances))
mean_abs = round(sum(abs(b) for b in balances) / len(balances))
else:
pct_zero = None
mean_abs = None
conf_pct = s["comp_globale"]["pct"]
# Combined score (SSO era: will weight per role/contract)
score = round(
(pct_zero or 0) * 0.6 + (conf_pct or 0) * 0.4
)
results.append({
"user_id": user_id,
"display_name": user_id.replace("_", " ").replace("-", " ").title(),
"n_semaines": len(balances),
"n_jours": s["n_jours"],
"pct_zero": pct_zero, # % weeks ≈ 0 HS — higher = better
"mean_abs_min": mean_abs, # mean abs(solde) in minutes — lower = better
"mean_abs_str": minutes_to_hhmm(mean_abs) if mean_abs is not None else "",
"conf_pct": conf_pct, # directive compliance % — higher = better
"score": score, # combined 0-100 — higher = better
"avg_delta": s["avg_delta"],
"avg_delta_min": s["avg_delta_min"],
})
results.sort(key=lambda r: -r["score"])
return results