MSIN-4379 — Refactor team mode handling to ensure unique bib assignment based on team name, enhancing batch processing logic. Update version code to 4.72.912.

This commit is contained in:
2026-07-30 09:02:39 -04:00
parent 39cf05979e
commit 8f3f7d4e83
2 changed files with 142 additions and 39 deletions

View File

@ -6337,15 +6337,20 @@ function fxBibSqlNoBibUnsigned($strColumn = 'no_bib') {
/**
* 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).
* Équipe « 1 équipe = 1 dossard » (epr_bib_team_mode = 3) : une équipe = une unité (nom d'équipe).
*/
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)";
$strTeamName = "TRIM(IFNULL(NULLIF(c2.pec_nom_equipe, ''), IFNULL(p2.par_nom_equipe, '')))";
$strTeamUnit = "IF($strTeamName <> '', LOWER($strTeamName), CONCAT('pec:', IF(p2.pec_id > 0, p2.pec_id, p2.par_id)))";
return "(CASE WHEN $strTeamMode = 3 THEN (
SELECT COUNT(DISTINCT IF(p2.pec_id > 0, p2.pec_id, p2.par_id))
SELECT COUNT(DISTINCT $strTeamUnit)
FROM resultats_participants p2
LEFT JOIN resultats_epreuves_commandees c2
ON c2.pec_id_original = p2.pec_id
AND c2.epr_id = p2.epr_id
WHERE p2.epr_id = ($strEprIdExpr)
AND $strBibP2 = ($strBibNumExpr)
AND p2.is_cancelled = 0
@ -7939,20 +7944,23 @@ function fxAssignAutoBibForParticipant($epr_id, $par_id) {
$teamMode = 1;
}
$teamKey = fxGetBatchTeamKey($p);
$foundBib = null;
$teamNumber = 0;
// Mode équipe 3 : reprendre le dossard déjà posé sur un coéquipier.
if ($isTeamEvent && $teamMode === 3 && $teamKey > 0) {
$existingBib = fxGetExistingTeamBibInDb($epr_id, $teamKey);
// Mode équipe 3 : reprendre le dossard déjà posé sur un coéquipier (même nom d'équipe).
$strShareKey = '';
if ($isTeamEvent && $teamMode === 3) {
$strShareKey = fxGetBatchTeamShareKey($p);
if ($strShareKey !== '') {
$existingBib = fxGetExistingTeamBibByShareKeyInDb($epr_id, $p);
if ($existingBib !== null && (int)$existingBib > 0) {
$foundBib = (int)$existingBib;
$teamNumber = $foundBib;
if ($existingBib !== null && (int)$existingBib > 0) {
$foundBib = (int)$existingBib;
$teamNumber = $foundBib;
if (fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib) <= 0) {
return ['success' => false, 'message' => 'assignation équipe impossible'];
if (fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib) <= 0) {
return ['success' => false, 'message' => 'assignation équipe impossible'];
}
}
}
}
@ -7991,6 +7999,7 @@ function fxAssignAutoBibForParticipant($epr_id, $par_id) {
return ['success' => false, 'message' => 'aucun dossard disponible'];
}
$teamKey = fxGetBatchTeamKey($p);
if ($isTeamEvent && $teamKey > 0) {
$updatedTeams = [];
@ -8056,18 +8065,23 @@ function fxInfosBibEpreuve($epr_id){
&& (int)($tabEpreuve['epr_bib_team_mode'] ?? 1) === 3;
if ($blnTeamOneBib) {
// MSIN-4432 — aligné sur fxGetQuantites / fxCountBatchAssignUnits : une équipe = une unité.
// MSIN-4379 — 1 équipe = 1 dossard : unité = nom d'équipe (repli pec_id si nom vide).
$strTeamName = "TRIM(IFNULL(NULLIF(c.pec_nom_equipe, ''), IFNULL(p.par_nom_equipe, '')))";
$strTeamUnit = "IF($strTeamName <> '', LOWER($strTeamName), CONCAT('pec:', p.pec_id))";
$sql = "
SELECT
COUNT(DISTINCT p.pec_id) AS total,
COUNT(DISTINCT $strTeamUnit) AS total,
COUNT(DISTINCT CASE
WHEN p.no_bib IS NOT NULL AND p.no_bib > 0 THEN p.pec_id
WHEN p.no_bib IS NOT NULL AND p.no_bib > 0 THEN $strTeamUnit
ELSE NULL
END) AS avec_bib
FROM resultats_participants p
LEFT JOIN resultats_epreuves_commandees c
ON c.pec_id_original = p.pec_id
AND c.epr_id = p.epr_id
WHERE p.epr_id = $epr_id
AND p.is_cancelled = 0
AND p.pec_id > 0
AND p.rol_id NOT IN (3, 4)
";
$row = $objDatabase->fxGetRow($sql);
$intTotal = (int)($row['total'] ?? 0);
@ -8899,9 +8913,7 @@ function fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber) {
}
/**
* MSIN-4379 — Clé d'équipe pour le batch.
* Source de vérité = p.pec_id (tous les coéquipiers partagent le même).
* pec_id_original (jointure) n'est qu'un repli si pec_id absent.
* MSIN-4379 — Clé pec pour dossards individuels / écriture no_equipe sur la commande.
*/
function fxGetBatchTeamKey($p) {
$intPec = (int)($p['pec_id'] ?? 0);
@ -8912,9 +8924,39 @@ function fxGetBatchTeamKey($p) {
return (int)($p['pec_id_original'] ?? 0);
}
/**
* MSIN-4379 — Nom d'équipe affiché (colonne Équipe), source pour « 1 équipe = 1 dossard ».
*/
function fxGetBatchTeamDisplayName($p) {
$str = trim((string)($p['pec_nom_equipe'] ?? ''));
if ($str === '') {
$str = trim((string)($p['par_nom_equipe'] ?? ''));
}
return $str;
}
/**
* MSIN-4379 — Clé de partage mode 3 : nom d'équipe (insensible à la casse).
* Sans nom → pec_id seul (ne fusionne pas tous les « sans nom » ensemble).
*/
function fxGetBatchTeamShareKey($p) {
$strName = fxGetBatchTeamDisplayName($p);
if ($strName !== '') {
if (function_exists('mb_strtolower')) {
return 'n:' . mb_strtolower($strName, 'UTF-8');
}
return 'n:' . strtolower($strName);
}
$intPec = fxGetBatchTeamKey($p);
return $intPec > 0 ? 'p:' . $intPec : '';
}
/**
* MSIN-4379 — Persiste le mode équipe envoyé par l'UI (Simuler / GO).
* Évite la course : radio cochée mais save_team_mode AJAX pas encore terminé.
*
* @return int Mode effectif (1 ou 3), 0 si rien à appliquer
*/
@ -8939,7 +8981,57 @@ function fxBibSyncTeamModeFromRequest($epr_id) {
}
/**
* MSIN-4433 — Mode équipe 3 : dossard déjà posé sur un coéquipier (batch par paquets).
* MSIN-4433 / MSIN-4379 — Mode 3 : dossard déjà posé sur un coéquipier (même nom d'équipe).
*/
function fxGetExistingTeamBibByShareKeyInDb($epr_id, $p) {
global $objDatabase;
$epr_id = (int)$epr_id;
$sqlBibNum = fxBibSqlNoBibUnsigned('p.no_bib');
$strName = fxGetBatchTeamDisplayName($p);
$strEscName = $objDatabase->fxEscape($strName);
if ($epr_id <= 0) {
return null;
}
if ($strName !== '') {
$sql = "
SELECT $sqlBibNum
FROM resultats_participants p
LEFT JOIN resultats_epreuves_commandees c
ON c.pec_id_original = p.pec_id
AND c.epr_id = p.epr_id
WHERE p.epr_id = $epr_id
AND p.is_cancelled = 0
AND $sqlBibNum > 0
AND LOWER(TRIM(IFNULL(NULLIF(c.pec_nom_equipe, ''), IFNULL(p.par_nom_equipe, ''))))
= LOWER('$strEscName')
LIMIT 1
";
} else {
$teamKey = fxGetBatchTeamKey($p);
if ($teamKey <= 0) {
return null;
}
$sql = "
SELECT $sqlBibNum
FROM resultats_participants p
WHERE p.epr_id = $epr_id
AND p.pec_id = $teamKey
AND p.is_cancelled = 0
AND $sqlBibNum > 0
LIMIT 1
";
}
$bib = (int)$objDatabase->fxGetVar($sql);
return $bib > 0 ? $bib : null;
}
/**
* @deprecated MSIN-4379 — préférer fxGetExistingTeamBibByShareKeyInDb (nom d'équipe).
*/
function fxGetExistingTeamBibInDb($epr_id, $teamKey) {
global $objDatabase;
@ -9027,24 +9119,29 @@ function fxCountBatchAssignUnits($epr_id, $participants = null) {
$teams = [];
foreach ($participants as $p) {
$teamKey = fxGetBatchTeamKey($p);
$strShareKey = fxGetBatchTeamShareKey($p);
if ($teamKey > 0) {
$teams[$teamKey] = true;
if ($strShareKey !== '') {
$teams[$strShareKey] = true;
}
}
return count($teams);
}
$strTeamName = "TRIM(IFNULL(NULLIF(c.pec_nom_equipe, ''), IFNULL(p.par_nom_equipe, '')))";
$strTeamUnit = "IF($strTeamName <> '', LOWER($strTeamName), CONCAT('pec:', p.pec_id))";
return (int)$objDatabase->fxGetVar("
SELECT COUNT(DISTINCT p.pec_id)
SELECT COUNT(DISTINCT $strTeamUnit)
FROM resultats_participants p
LEFT JOIN resultats_epreuves_commandees c
ON c.pec_id_original = p.pec_id
AND c.epr_id = p.epr_id
WHERE p.epr_id = $epr_id
AND p.is_cancelled = 0
AND (p.no_bib IS NULL OR p.no_bib = '' OR p.no_bib = 0)
AND p.rol_id NOT IN (3, 4)
AND p.pec_id > 0
");
}
@ -9107,12 +9204,17 @@ function fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mo
$teamNumber = 0;
$foundBib = null;
// MSIN-4379 — Mode 1 équipe = 1 dossard : un numéro pour toute l'équipe (même pec_id).
if ($teamMode === 3 && $teamKey > 0) {
if (isset($teamBibMap[$teamKey])) {
$foundBib = $teamBibMap[$teamKey];
// MSIN-4379 — Mode 1 équipe = 1 dossard : regrouper sur le NOM d'équipe (colonne Équipe).
if ($teamMode === 3) {
$strShareKey = fxGetBatchTeamShareKey($p);
if ($strShareKey === '') {
continue;
}
if (isset($teamBibMap[$strShareKey])) {
$foundBib = $teamBibMap[$strShareKey];
} else {
$foundBib = fxGetExistingTeamBibInDb($epr_id, $teamKey);
$foundBib = fxGetExistingTeamBibByShareKeyInDb($epr_id, $p);
}
if ($foundBib === null) {
@ -9127,14 +9229,16 @@ function fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mo
if ($foundBib === null) {
break;
}
// Premier membre déjà écrit en execute par fxTryAssignNextBibForParticipant.
if ($mode === 'execute') {
$processedParIds[$par_id] = true;
$assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, $foundBib);
if ($teamKey > 0) {
fxApplyBatchTeamNumber($epr_id, $teamKey, $foundBib, $updatedTeams);
}
}
}
$teamBibMap[$teamKey] = (int)$foundBib;
$teamBibMap[$strShareKey] = (int)$foundBib;
$teamNumber = (int)$foundBib;
foreach ($participants as $mate) {
@ -9142,23 +9246,22 @@ function fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mo
if ($mateId <= 0 || isset($processedParIds[$mateId])) {
continue;
}
if (fxGetBatchTeamKey($mate) !== $teamKey) {
if (fxGetBatchTeamShareKey($mate) !== $strShareKey) {
continue;
}
if ($mode === 'execute') {
// 0 affected = déjà ce dossard (paquet précédent) : OK, on continue le regroupement.
fxApplyBatchParticipantBib($epr_id, $mateId, $teamNumber);
$matePec = fxGetBatchTeamKey($mate);
if ($matePec > 0) {
fxApplyBatchTeamNumber($epr_id, $matePec, $teamNumber, $updatedTeams);
}
}
$assignments[] = fxBuildBatchAssignmentRow($mate, $teamNumber, $teamNumber);
$processedParIds[$mateId] = true;
}
if ($mode === 'execute') {
fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams);
}
continue;
}

View File

@ -7,7 +7,7 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.911'); // MSIN-4379 — GO batch 1 équipe = 1 dossard (mode UI + regroupement)
define('_VERSION_CODE', '4.72.912'); // MSIN-4379 — 1 équipe = 1 dossard : regroupement sur nom d'équipe
define('_DATE_CODE', '2026-07-30');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');