diff --git a/ajax_bib_range.php b/ajax_bib_range.php index 78bc912..5997e3f 100644 --- a/ajax_bib_range.php +++ b/ajax_bib_range.php @@ -35,6 +35,7 @@ $arrBibAjaxActions = [ 'reset_preview', 'reset_apply', 'reset_all_apply', + 'save_allow_inter_epr', 'save_team_mode', 'toggle_lock', 'save_auto_config', @@ -257,7 +258,7 @@ if ($action == 'save') { // ===================== // VALIDATION 4 — OVERLAP pas de double epreuves // ===================== - $tabOverlaps = fxBibGetOverlappingRanges($eve_id, $start, $end, $is_new ? 0 : $id); + $tabOverlaps = fxBibGetOverlappingRanges($eve_id, $start, $end, $is_new ? 0 : $id, $epr_id); if (!empty($tabOverlaps)) { echo json_encode([ @@ -356,6 +357,41 @@ if ($action == 'batch_analysis') { exit; } +// ===================== +// MSIN-4424 — Réglage doublons inter-épreuves (événement) +// ===================== +if ($action == 'save_allow_inter_epr') { + + $int_eve_id = (int)($_POST['eve_id'] ?? 0); + $blnAllow = !empty($_POST['allow']) && (string)$_POST['allow'] !== '0'; + + if ($int_eve_id <= 0) { + echo json_encode([ + 'success' => false, + 'message' => fxBibMsg('bib_v4_ajax_epr_invalid'), + ]); + exit; + } + + $result = fxBibSetEventAllowsInterEprDuplicates($int_eve_id, $blnAllow); + + if (empty($result['success'])) { + echo json_encode($result); + exit; + } + + $strLangueAnom = $_SESSION['lang'] ?? 'fr'; + $tabAnomalies = fxBibCollectAnomalies($int_eve_id, $strLangueAnom); + + echo json_encode([ + 'success' => true, + 'allow_inter_epr' => !empty($result['allow_inter_epr']) ? 1 : 0, + 'anomalies_html' => renderBibAnomaliesPanel($int_eve_id, $strLangueAnom, $tabAnomalies), + 'anomaly_count' => fxBibAnomalyTotalCount($tabAnomalies), + ]); + exit; +} + // MSIN-4436 — Panneau assignation globale (chargement différé à l'ouverture). if ($action == 'global_batch_panel') { diff --git a/ajax_inscr_gestion.php b/ajax_inscr_gestion.php index db51a7c..a551c85 100644 --- a/ajax_inscr_gestion.php +++ b/ajax_inscr_gestion.php @@ -147,7 +147,11 @@ switch ($strAction) { . ' WHERE p.par_id = ' . $intParId . ' AND p.pec_id = e.pec_id_original LIMIT 1' )); - $arrDup = fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intPecOrig, $blnTeam); + $intCurrentEprId = (int)$objDatabase->fxGetVar( + 'SELECT epr_id FROM resultats_participants WHERE par_id = ' . $intParId . ' LIMIT 1' + ); + + $arrDup = fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intPecOrig, $blnTeam, $intCurrentEprId); $arrWho = array(); foreach ($arrDup as $rowDup) { $arrWho[] = array( diff --git a/css/style.css b/css/style.css index b1aaac5..3046aad 100644 --- a/css/style.css +++ b/css/style.css @@ -1064,6 +1064,39 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active { line-height:1.45; } +/* MSIN-4424 — Bandeau réglages dossards (haut du module). */ +.bib-event-settings{ + border:1px solid #c8d6e5; + border-radius:6px; + background:#f8fafc; + padding:10px 14px; + margin-bottom:4px; +} + +.bib-event-settings__label{ + display:flex; + align-items:flex-start; + gap:8px; + margin:0; + font-weight:600; + font-size:14px; + line-height:1.4; + cursor:pointer; +} + +.bib-event-settings__label input[type="checkbox"]{ + margin-top:3px; + flex-shrink:0; +} + +.bib-event-settings__text{ + flex:1 1 auto; +} + +.bib-anomaly-block--inter-epr-dupes .bib-anomaly-block-title{ + color:#8a3b12; +} + /* MSIN-4436 — Assignation globale (épreuves solo) */ .bib-global-batch{ border:1px solid #c8d6e5; diff --git a/js/v2/bib-assignments.js b/js/v2/bib-assignments.js index b5746f7..9b2912f 100644 --- a/js/v2/bib-assignments.js +++ b/js/v2/bib-assignments.js @@ -2711,6 +2711,49 @@ }); }); + // MSIN-4424 — Autoriser mêmes numéros entre épreuves (réglage événement). + let chkAllowInterEpr = moduleBib.querySelector('.bib-event-allow-inter-epr'); + if (chkAllowInterEpr) { + chkAllowInterEpr.addEventListener('change', function () { + let eveId = moduleBib.dataset.eveId || ''; + if (!eveId) { + return; + } + + bibFetch('/ajax_bib_range.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: + 'action=save_allow_inter_epr' + + '&eve_id=' + encodeURIComponent(eveId) + + '&allow=' + (chkAllowInterEpr.checked ? '1' : '0') + + bibAjaxLangSuffix() + }) + .then(function (res) { return res.json(); }) + .then(function (data) { + if (!data.success) { + chkAllowInterEpr.checked = !chkAllowInterEpr.checked; + alert(data.message || bibJs('jsErrGeneric')); + return; + } + + moduleBib.dataset.allowInterEpr = data.allow_inter_epr ? '1' : '0'; + + let mount = document.getElementById('bib-anomalies-mount'); + if (mount && data.anomalies_html) { + mount.innerHTML = data.anomalies_html; + initModuleBibTippy(mount); + } + }) + .catch(function () { + chkAllowInterEpr.checked = !chkAllowInterEpr.checked; + alert(bibJs('jsErrGeneric')); + }); + }); + } + // MSIN-4436 — Anomalies : coquille légère au chargement, détail en AJAX. if (document.querySelector('#bib-anomalies-panel[data-bib-anomalies-deferred="1"]')) { refreshBibAnomaliesPanel(); diff --git a/php/inc_fx_inscriptions_gestion.php b/php/inc_fx_inscriptions_gestion.php index 6e19fae..8dd6a97 100644 --- a/php/inc_fx_inscriptions_gestion.php +++ b/php/inc_fx_inscriptions_gestion.php @@ -619,10 +619,12 @@ function fxInscrGestionBibDuplicatePolicy($intEveId) { * @param bool $blnTeam true = dossard d'equipe (e.no_equipe), false = individuel (p.no_bib) * @return array liste de lignes ['par_nom','par_prenom','epr_id'] */ -function fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intExceptPec, $blnTeam) { +function fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intExceptPec, $blnTeam, $intCurrentEprId = 0) { global $objDatabase; $strNoBib = trim((string)$strNoBib); + $intCurrentEprId = (int)$intCurrentEprId; + if (intval($intEveId) <= 0 || $strNoBib === '') { return array(); } @@ -639,7 +641,25 @@ function fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intExceptPec, $b . ' ORDER BY p.par_nom, p.par_prenom'; $tab = $objDatabase->fxGetResults($sql); - return is_array($tab) ? $tab : array(); + if (!is_array($tab) || empty($tab)) { + return array(); + } + + $blnAllowInter = function_exists('fxBibEventAllowsInterEprDuplicates') + && fxBibEventAllowsInterEprDuplicates($intEveId); + + $arrOut = array(); + foreach ($tab as $rowDup) { + $intDupEprId = (int)($rowDup['epr_id'] ?? 0); + + if ($intCurrentEprId > 0 && $intDupEprId !== $intCurrentEprId && $blnAllowInter) { + continue; + } + + $arrOut[] = $rowDup; + } + + return $arrOut; } function fxInscrGestionEpreuveLabel($intEprId, $strLangue) { diff --git a/php/inc_fx_promoteur.php b/php/inc_fx_promoteur.php index 3557c9a..730b808 100644 --- a/php/inc_fx_promoteur.php +++ b/php/inc_fx_promoteur.php @@ -1539,8 +1539,27 @@ function fxShowDupes($int_eve_id) { $strPage = '/account'; } - $sqlNoBib = "SELECT no_bib, epr_id, COUNT(*) c FROM resultats_participants where eve_id = " . intval($int_eve_id) . " AND no_bib <> '' GROUP BY no_bib HAVING c > 1"; - $tabNoBib = $objDatabase->fxGetResults($sqlNoBib); + $sqlNoBib = "SELECT no_bib, epr_id, COUNT(*) c FROM resultats_participants where eve_id = " . intval($int_eve_id) . " AND no_bib <> '' AND is_cancelled = 0 GROUP BY no_bib, epr_id HAVING c > 1"; + $tabIntraDupes = $objDatabase->fxGetResults($sqlNoBib); + + $tabInterDupes = []; + if (!fxBibEventAllowsInterEprDuplicates((int)$int_eve_id)) { + $sqlInter = "SELECT no_bib FROM resultats_participants WHERE eve_id = " . intval($int_eve_id) + . " AND no_bib <> '' AND is_cancelled = 0 GROUP BY no_bib HAVING COUNT(DISTINCT epr_id) > 1"; + $tabInterDupes = $objDatabase->fxGetResults($sqlInter); + } + + $tabBibKeys = []; + if (is_array($tabIntraDupes)) { + foreach ($tabIntraDupes as $row) { + $tabBibKeys[(int)$row['no_bib']] = true; + } + } + if (is_array($tabInterDupes)) { + foreach ($tabInterDupes as $row) { + $tabBibKeys[(int)$row['no_bib']] = true; + } + } ?>