implentation tour pas fini

This commit is contained in:
2025-12-12 09:52:22 -05:00
parent 5873ab4900
commit f85cd66795
7 changed files with 268 additions and 111 deletions

15
a faire Normal file
View File

@ -0,0 +1,15 @@
Notes pour correction du moteur Python
Les priorités ne fonctionnent pas.
La logique actuelle doit être revue.
La validation des intervalles est mal faite.
Elle doit être basée directement sur lheure pour obtenir un rapprochement plus uniforme.
Les tours ne fonctionnent pas.
Le calcul du tour et du temps de tour doit être revu complètement.
Concept général à corriger :
Lorsquune entrée est jugée « bonne », on doit lécrire immédiatement dans la base de données,
avant dappliquer nimporte quelle autre validation.
Parce que ces lectures doivent être conservées quoi quil arrive.

View File

@ -87,7 +87,7 @@ def insert_detail_record(
try:
cur.execute(sql, data)
cnx.commit()
return cur.lastrowid
except mysql.connector.IntegrityError as e:
# Duplicate key = lecture déjà traitée → on ignore et on continue
if e.errno == 1062:

View File

@ -11,18 +11,14 @@ from zoneinfo import ZoneInfo
from decimal import Decimal
from engine.utils import format_temps_decimal
from engine.engine_components.regles import resolve_priority
from engine.engine_components.regles import check_interval_rule
from engine.engine_components.regles import get_last_valid_lecture_time
from engine.engine_components.regles import ts_to_utc
from engine.engine_components.regles import update_detail_status_zero
LOCAL_TZ = ZoneInfo("America/Toronto")
# -------------------------------------------------
# Conversion d'un timestamp Decimal en datetime UTC
# -------------------------------------------------
def ts_to_utc(ts):
ts = Decimal(str(ts))
seconds = int(ts)
micro = int((ts - Decimal(seconds)) * Decimal(1_000_000))
return datetime.fromtimestamp(seconds, tz=timezone.utc).replace(microsecond=micro)
# -------------------------------------------------
@ -128,8 +124,11 @@ def process_course(cur, cnx, con_id: int):
coureur = get_classement_by_tag(cur, classement_table, tag)
if not coureur:
continue
dossard = "???"
status = 0
reason_code = "UNKNOWN_BIB"
reason_ref_id = None
else:
dossard = coureur["cla_info_dossard"]
# -------------------------------------------------
@ -148,14 +147,9 @@ def process_course(cur, cnx, con_id: int):
detail_table = f"resultv2_{con_id}_detail"
# -------------------------------------------------
# Règle de priorité
# 🔥 INSÉRER IMMÉDIATEMENT DANS DETAILS 🔥
# -------------------------------------------------
status, reason_code, reason_ref_id, forced_tour = resolve_priority(
cur, cnx, detail_table, tp_id, dossard, timestamp, prio, det_id, tp_config
)
if status == 0:
insert_detail_record(
detail_id=insert_detail_record(
cur, cnx, con_id,
dossard, lec,
tp_id, tp_name,
@ -168,7 +162,21 @@ def process_course(cur, cnx, con_id: int):
tempstour=None,
tempstour_str=None
)
continue
# 👉 Après ceci, TU CONTINUES TA LOGIQUE (priorité, intervalle, tours)
# mais la donnée brute est déjà sauvée.
# on traite pas les dossard ???
if dossard != "???":
# -------------------------------------------------
# Règle de priorité
# -------------------------------------------------
#status, reason_code, reason_ref_id, forced_tour = resolve_priority(
# cur, cnx, detail_table, tp_id, dossard, timestamp, prio, det_id, tp_config
#)
# -------------------------------------------------
# Règle d'intervalle
@ -186,54 +194,85 @@ def process_course(cur, cnx, con_id: int):
except:
interval_sec = 0
last_dt = get_last_valid_lecture_time(cur, detail_table, tp_id, dossard)
# Appel de la règle dintervalle
status_interval, rc_interval, rr_interval = check_interval_rule(
cur,
detail_table,
tp_id,
dossard,
timestamp,
interval_sec,
det_id
if last_dt and interval_sec > 0:
delta = (dt_utc - last_dt).total_seconds()
if delta < interval_sec:
status = 0
reason_code = f"SKIP_INTERVAL {delta:.1f}s < {interval_sec}s"
reason_ref_id = det_id
insert_detail_record(
cur, cnx, con_id,
dossard, lec,
tp_id, tp_name,
chr_loc, prio, controller,
dt_utc,
status=status,
reason_code=reason_code,
reason_ref_id=reason_ref_id,
tour=None,
tempstour=None,
tempstour_str=None
)
# Si la règle dintervalle rejette
if status_interval == 0:
update_detail_status_zero(
cur,
cnx,
detail_table,
detail_id, # <-- l'ID que tu as obtenu juste après insert_detail_record
rc_interval, # reason_code retourné par la règle
rr_interval # reason_ref_id retourné par la règle
)
# Et on arrête le traitement de cette lecture
continue
# -------------------------------------------------
# Calcul tour (placeholder)
# -------------------------------------------------
tour = 1
tempstour = Decimal("0")
tempstour_str = "0"
insert_detail_record(
cur, cnx, con_id,
dossard, lec,
tp_id, tp_name,
chr_loc, prio, controller,
dt_utc,
status=status,
reason_code=reason_code,
reason_ref_id=reason_ref_id,
tour=tour,
tempstour=tempstour,
tempstour_str=tempstour_str
# -------------------------------------------------
# Calcul du tour + temps de tour
# -------------------------------------------------
# Appel de la règle tour
status_tour = check_tour_rule(
cur,
detail_table,
tp_id,
dossard,
timestamp,
det_id
)
# Si la règle dtour rejette
if status_interval == 0:
update_detail_status_zero(
cur,
cnx,
detail_table,
detail_id, # <-- l'ID que tu as obtenu juste après insert_detail_record
rc_interval, # reason_code retourné par la règle
rr_interval # reason_ref_id retourné par la règle
)
# Et on arrête le traitement de cette lecture
continue
#tour, prev_ts = compute_tour(cur, detail_table, tp_id, dossard)
#if forced_tour is not None:
# tour = forced_tour
#if prev_ts is None:
# tempstour = Decimal("0")
#else:
# tempstour = timestamp - prev_ts
#tempstour_str = format_temps_decimal(tempstour)
if status == 1:
log_info(f"[OK] id={rcourse_id} tag={tag} dossard={dossard} tp={tp_name} prio={prio}")
else:
log_info(f"[dossard ???] id={rcourse_id} ")
# -------------------------------------------------
# Mise à jour du pointeur
@ -242,25 +281,4 @@ def process_course(cur, cnx, con_id: int):
# -------------------------------------------------
# Dernière lecture valide
# -------------------------------------------------
def get_last_valid_lecture_time(cur, detail_table, tp_id, dossard):
cur.execute(f"""
SELECT timestamp_read
FROM `{detail_table}`
WHERE tp_id = %s
AND cla_info_dossard = %s
AND status = 1
ORDER BY detail_id DESC
LIMIT 1
""", (tp_id, dossard))
row = cur.fetchone()
if not row:
return None
ts_decimal = Decimal(str(row["timestamp_read"]))
return ts_to_utc(ts_decimal)

View File

@ -1,5 +1,7 @@
# regles.py
from engine.logger import log_info, log_debug
from decimal import Decimal
from datetime import datetime, timezone
# -------------------------------------------------
# Règle de priorité : remplace, rejette, ou force tour
# -------------------------------------------------
@ -95,3 +97,125 @@ def resolve_priority(
# Même priorité → rejet
return 0, "EQUAL_PRIORITY", det_id, None
# -------------------------------------------------
# Regle interval
# ------------------------------------------------
def check_interval_rule(cur, detail_table, tp_id, dossard, timestamp, interval_sec, det_id):
"""
Retourne :
status (1 ou 0)
reason_code
reason_ref_id
"""
log_debug(f"[INTERVAL] tp_id={tp_id} dossard={dossard} interval_sec={interval_sec}")
last_timestamp = get_last_valid_lecture_time(cur, detail_table, tp_id, dossard, timestamp)
log_debug(f"[INTERVAL] last_valid={last_timestamp} current={timestamp}")
if last_timestamp and interval_sec > 0:
delta = (timestamp - last_timestamp)
log_debug(f"[INTERVAL] delta={delta:.3f}s")
if delta < interval_sec:
reason = f"SKIP_INTERVAL {delta:.1f}s < {interval_sec}s"
log_debug(
f"[INTERVAL] REJECT dossard={dossard} tp_id={tp_id} "
f"reason='{reason}' det_id={det_id}"
)
return (0, reason, det_id)
log_debug(f"[INTERVAL] OK dossard={dossard} tp_id={tp_id}")
return (1, None, None)
# -------------------------------------------------
# Dernière lecture valide (timestamp_read < T)
# -------------------------------------------------
def get_last_valid_lecture_time(cur, detail_table, tp_id, dossard, current_ts):
log_debug(f"[get_last_valid_lecture_time] tp={tp_id} dossard={dossard} current={current_ts}")
cur.execute(f"""
SELECT timestamp_read
FROM `{detail_table}`
WHERE tp_id = %s
AND cla_info_dossard = %s
AND status = 1
AND timestamp_read < %s
ORDER BY timestamp_read DESC
LIMIT 1
""", (tp_id, dossard, current_ts))
log_debug(
f"SELECT timestamp_read FROM `{detail_table}` "
f"WHERE tp_id = {tp_id} AND cla_info_dossard = '{dossard}' "
f"AND status = 1 AND timestamp_read < {current_ts} "
f"ORDER BY timestamp_read DESC LIMIT 1;"
)
row = cur.fetchone()
log_debug(f"[get_last_valid_lecture_time] result={row}")
if not row:
return None
return Decimal(str(row["timestamp_read"]))
# -------------------------------------------------
# Conversion d'un timestamp Decimal en datetime UTC
# -------------------------------------------------
def ts_to_utc(ts):
ts = Decimal(str(ts))
seconds = int(ts)
micro = int((ts - Decimal(seconds)) * Decimal(1_000_000))
return datetime.fromtimestamp(seconds, tz=timezone.utc).replace(microsecond=micro)
# -------------------------------------------------
# Recherche du dernier tour pour un coureur à un TP
# -------------------------------------------------
#def compute_tour(cur, detail_table, tp_id, dossard):
def check_tour_rule(
cur,
detail_table,
tp_id,
dossard,
timestamp,
det_id
):
cur.execute(f"""
SELECT tour, timestamp_read
FROM `{detail_table}`
WHERE tp_id = %s
AND cla_info_dossard = %s
AND status = 1
ORDER BY detail_id DESC
LIMIT 1
""", (tp_id, dossard))
row = cur.fetchone()
if not row or row["tour"] is None:
return 1, None
last_tour = row["tour"]
prev_ts = Decimal(str(row["timestamp_read"]))
return last_tour + 1, prev_ts
def update_detail_status_zero(cur, cnx, detail_table, detail_id, reason_code, reason_ref_id):
"""
Met à jour un enregistrement Detail existant pour le passer en status=0,
avec reason_code et reason_ref_id.
"""
cur.execute(f"""
UPDATE `{detail_table}`
SET status = 0,
reason_code = %s,
reason_ref_id = %s
WHERE detail_id = %s
""", (reason_code, reason_ref_id, detail_id))
cnx.commit()