From fd1d1368422622598de8653d736b7bc51427d995 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 19 Jun 2026 10:56:09 -0400 Subject: [PATCH] Add SQL functions for duplicate unit count and anomaly detection in bib management This commit introduces two new SQL functions: `fxBibSqlDuplicateUnitCount`, which counts the number of units sharing a `no_bib` for an event, and `fxBibSqlIsBibDuplicateAnomaly`, which checks for duplicate anomalies excluding legitimate team sharing. These functions enhance the existing bib management logic by improving the accuracy of duplicate detection. Additionally, the existing SQL queries in `fxInfosBibRange` and `fxBibAnomalyDuplicateBibs` are updated to utilize the new functions for better clarity and efficiency. --- php/inc_fx_promoteur.php | 46 ++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/php/inc_fx_promoteur.php b/php/inc_fx_promoteur.php index 6ef83b2..e08d226 100644 --- a/php/inc_fx_promoteur.php +++ b/php/inc_fx_promoteur.php @@ -3844,6 +3844,35 @@ function fxBibSqlNoBibUnsigned($strColumn = 'no_bib') { return "CAST(NULLIF(TRIM($strColumn), '') AS UNSIGNED)"; } +/** + * SQL — nombre d'unités partageant un no_bib pour une épreuve. + * Solo / équipe « dossards individuels » : une personne = une unité (COUNT participants). + * Équipe « 1 équipe = 1 dossard » (epr_bib_team_mode = 3) : une équipe = une unité (DISTINCT pec_id). + */ +function fxBibSqlDuplicateUnitCount($strEprIdExpr, $strBibNumExpr) { + $strBibP2 = fxBibSqlNoBibUnsigned('p2.no_bib'); + $strTeamMode = "(SELECT CASE WHEN e.epr_equipe = 1 THEN IFNULL(NULLIF(e.epr_bib_team_mode, 0), 1) ELSE 1 END FROM inscriptions_epreuves e WHERE e.epr_id = ($strEprIdExpr) LIMIT 1)"; + + return "(CASE WHEN $strTeamMode = 3 THEN ( + SELECT COUNT(DISTINCT IF(p2.pec_id > 0, p2.pec_id, p2.par_id)) + FROM resultats_participants p2 + WHERE p2.epr_id = ($strEprIdExpr) + AND $strBibP2 = ($strBibNumExpr) + AND p2.is_cancelled = 0 + ) ELSE ( + SELECT COUNT(*) + FROM resultats_participants p2 + WHERE p2.epr_id = ($strEprIdExpr) + AND $strBibP2 = ($strBibNumExpr) + AND p2.is_cancelled = 0 + ) END)"; +} + +/** SQL — vrai doublon (anomalie), hors partage légitime entre coéquipiers (mode équipe 3). */ +function fxBibSqlIsBibDuplicateAnomaly($strEprIdExpr, $strBibNumExpr) { + return fxBibSqlDuplicateUnitCount($strEprIdExpr, $strBibNumExpr) . ' > 1'; +} + function fxInfosBibRange($epr_id = 0, $epr_bib_id = 0){ global $objDatabase, $vDomaine; @@ -3865,7 +3894,6 @@ function fxInfosBibRange($epr_id = 0, $epr_bib_id = 0){ $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $sqlBibNumRp = fxBibSqlNoBibUnsigned('rp.no_bib'); - $sqlBibNumRp2 = fxBibSqlNoBibUnsigned('rp2.no_bib'); $sqlBibStats = " SELECT @@ -3949,13 +3977,9 @@ function fxInfosBibRange($epr_id = 0, $epr_bib_id = 0){ SELECT GROUP_CONCAT(DISTINCT $sqlBibNumRp ORDER BY $sqlBibNumRp SEPARATOR ',') FROM resultats_participants rp WHERE rp.epr_id = b.epr_id + AND rp.is_cancelled = 0 AND $sqlBibNumRp BETWEEN b.epr_bib_start AND b.epr_bib_finish - AND ( - SELECT COUNT(*) - FROM resultats_participants rp2 - WHERE rp2.epr_id = rp.epr_id - AND $sqlBibNumRp2 = $sqlBibNumRp - ) > 1 + AND " . fxBibSqlIsBibDuplicateAnomaly('rp.epr_id', $sqlBibNumRp) . " ) AS liste_doublons FROM inscriptions_epreuves_bib b @@ -4033,13 +4057,7 @@ function fxBibAnomalyDuplicateBibs($int_eve_id, $strLangue = 'fr') { WHERE e.eve_id = $int_eve_id AND b.epr_bib_start IS NOT NULL AND b.epr_bib_finish IS NOT NULL - AND ( - SELECT COUNT(*) - FROM resultats_participants p2 - WHERE p2.epr_id = b.epr_id - AND p2.is_cancelled = 0 - AND " . fxBibSqlNoBibUnsigned('p2.no_bib') . " = $sqlBibNumP - ) > 1 + AND " . fxBibSqlIsBibDuplicateAnomaly('b.epr_id', $sqlBibNumP) . " ORDER BY b.epr_id, b.epr_bib_start, $sqlBibNumP, p.par_nom, p.par_prenom ";