MSIN-4445 — Refine free assignment logic by enhancing duplicate bib number checks and improving feedback mechanisms for overlapping ranges. Update backend functions to ensure accurate detection of assigned bibs within specified ranges and adjust UI components to reflect these changes. Increment version code to 4.72.830.

This commit is contained in:
2026-07-16 10:02:14 -04:00
parent ce63b9325e
commit 527e3909e8
4 changed files with 90 additions and 41 deletions

View File

@ -714,10 +714,29 @@ if ($action == 'batch_global_free_analysis') {
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart || $strSort1 === '' || empty($tabEprIds)) {
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
echo json_encode([
'success' => false,
'message' => fxBibMsg('bib_v4_global_batch_free_plan_invalid'),
'duplicates' => ['has' => false, 'count' => 0, 'message' => ''],
]);
exit;
}
// MSIN-4445 — Doublons basés sur la plage entière (même si tri / épreuves incomplets).
$tabDupesOnly = fxBibFreeDuplicateRisk($int_eve_id, [], $intStart, $intEnd);
if ($strSort1 === '') {
$strSort1 = 'ba:2';
}
if (empty($tabEprIds)) {
echo json_encode([
'success' => true,
'info' => $tabDupesOnly['message'],
'stats' => ['nb_epreuves' => 0, 'nb_participants' => 0, 'nb_bibs' => 0],
'feedback' => fxBibFreeQtyFeedback($intEnd - $intStart + 1, 0),
'duplicates' => $tabDupesOnly,
]);
exit;
}

View File

@ -1289,20 +1289,34 @@
function bibSetGlobalFreeDupesWarn(section, blnShow, strMessage) {
var fields = bibGetGlobalBatchFreeRangeFields(section);
if (!fields || !fields.dupesEl) {
if (!fields) {
return;
}
if (!blnShow) {
fields.dupesEl.textContent = '';
fields.dupesEl.classList.add('bib-ui-hidden');
return;
}
fields.dupesEl.textContent = strMessage
var msg = strMessage
|| bibJs('jsGlobalFreeDupesWarn')
|| 'Attention : vous êtes en train de créer des inscriptions avec des dossards en double.';
fields.dupesEl.classList.remove('bib-ui-hidden');
if (fields.dupesEl) {
if (!blnShow) {
fields.dupesEl.textContent = '';
fields.dupesEl.classList.add('bib-ui-hidden');
} else {
fields.dupesEl.textContent = msg;
fields.dupesEl.classList.remove('bib-ui-hidden');
}
return;
}
// Repli si l'ancien markup n'a pas la ligne dédiée.
if (fields.feedback && blnShow) {
var base = (fields.qtyEl && fields.qtyEl.textContent)
? fields.qtyEl.textContent
: (fields.feedback.textContent || '');
fields.feedback.textContent = base
? (base + ' — ' + msg)
: msg;
}
}
function bibUpdateGlobalFreeQtyFeedback(section) {
@ -1551,6 +1565,7 @@
data.message || bibJs('jsErrGeneric'),
'error'
);
bibSetGlobalFreeDupesWarn(section, false);
return data;
}

View File

@ -61,68 +61,83 @@ function fxBibFreeQtyFeedbackMessage(array $tabFeedback) {
}
/**
* MSIN-4445 — Nombre de dossards de la plage déjà utilisés sur une autre épreuve.
* Ces numéros seraient réassignés (doublon inter-épreuve) car le batch ne les saute pas.
* MSIN-4445 — Nombre de dossards déjà assignés dans [start, end] pour l'événement.
* Jointure via épreuve : plus fiable que p.eve_id seul.
*/
function fxBibCountBibsUsedOutsideEpr($int_eve_id, $intStart, $intEnd, $intEprId) {
function fxBibCountAssignedBibsInRange($int_eve_id, $intStart, $intEnd) {
global $objDatabase;
$int_eve_id = (int)$int_eve_id;
$intStart = (int)$intStart;
$intEnd = (int)$intEnd;
$intEprId = (int)$intEprId;
if ($int_eve_id <= 0 || $intEprId <= 0 || $intStart <= 0 || $intEnd < $intStart) {
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
return 0;
}
$sqlBib = fxBibSqlNoBibUnsigned('no_bib');
$sqlBib = fxBibSqlNoBibUnsigned('p.no_bib');
return (int)$objDatabase->fxGetVar("
SELECT COUNT(DISTINCT $sqlBib)
FROM resultats_participants
WHERE eve_id = $int_eve_id
AND epr_id <> $intEprId
AND is_cancelled = 0
AND no_bib IS NOT NULL
AND TRIM(no_bib) <> ''
FROM resultats_participants p
INNER JOIN inscriptions_epreuves e ON e.epr_id = p.epr_id
WHERE e.eve_id = $int_eve_id
AND IFNULL(p.is_cancelled, 0) = 0
AND p.no_bib IS NOT NULL
AND TRIM(p.no_bib) <> ''
AND $sqlBib BETWEEN $intStart AND $intEnd
");
}
/**
* MSIN-4445 — Risque de doublons pour le plan libre (plages virtuelles vs dossards déjà pris ailleurs).
* MSIN-4445 — Risque de doublons pour une plage libre.
* Avertit si des dossards de la plage sont déjà portés, ou si une séquence
* existante chevauche la plage (même hors épreuves sélectionnées).
*
* @return array{has:bool, count:int, message:string}
*/
function fxBibFreeDuplicateRisk($int_eve_id, $tabPlan) {
function fxBibFreeDuplicateRisk($int_eve_id, $tabPlan, $intStart = 0, $intEnd = 0) {
$int_eve_id = (int)$int_eve_id;
$intCount = 0;
$intStart = (int)$intStart;
$intEnd = (int)$intEnd;
if (!is_array($tabPlan)) {
if ($intStart <= 0 || $intEnd < $intStart) {
// Repli : bornes du plan si Début/Fin absents.
foreach ((array)$tabPlan as $item) {
if (!empty($item['skip'])) {
continue;
}
$intItemStart = (int)($item['start'] ?? 0);
$intItemEnd = (int)($item['end'] ?? 0);
if ($intItemStart <= 0 || $intItemEnd < $intItemStart) {
continue;
}
if ($intStart <= 0 || $intItemStart < $intStart) {
$intStart = $intItemStart;
}
if ($intItemEnd > $intEnd) {
$intEnd = $intItemEnd;
}
}
}
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
return ['has' => false, 'count' => 0, 'message' => ''];
}
foreach ($tabPlan as $item) {
if (!empty($item['skip'])) {
continue;
}
$intCount = fxBibCountAssignedBibsInRange($int_eve_id, $intStart, $intEnd);
$intCount += fxBibCountBibsUsedOutsideEpr(
$int_eve_id,
(int)($item['start'] ?? 0),
(int)($item['end'] ?? 0),
(int)($item['epr_id'] ?? 0)
);
}
// Séquences déjà configurées qui chevauchent la plage (autre épreuve).
$tabOverlaps = fxBibGetOverlappingRanges($int_eve_id, $intStart, $intEnd, 0, 0);
$intOverlapSeq = is_array($tabOverlaps) ? count($tabOverlaps) : 0;
if ($intCount <= 0) {
if ($intCount <= 0 && $intOverlapSeq <= 0) {
return ['has' => false, 'count' => 0, 'message' => ''];
}
return [
'has' => true,
'count' => $intCount,
'count' => max($intCount, $intOverlapSeq),
'message' => fxBibMsg('bib_v4_global_batch_free_dupes_warn'),
];
}
@ -262,7 +277,7 @@ function fxBibBuildGlobalBatchFreeAnalysis($int_eve_id, $tabPlan, $intStart, $in
}
$tabFeedback = fxBibFreeQtyFeedback($intQty, $intPendingAll);
$tabDupes = fxBibFreeDuplicateRisk($int_eve_id, $tabPlan);
$tabDupes = fxBibFreeDuplicateRisk($int_eve_id, $tabPlan, $intStart, $intEnd);
return [
'stats' => $tabStats,

View File

@ -7,7 +7,7 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.829');
define('_VERSION_CODE', '4.72.830');
define('_DATE_CODE', '2026-07-16');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');