MSIN-4406 Implement duplicate bib check feature in registration management
This commit introduces a new AJAX functionality to check for duplicate bib numbers during the registration process. It adds a case in `ajax_inscr_gestion.php` to handle duplicate checks, returning relevant participant information and policies for handling duplicates. The front-end script in `inc_footer_scripts.php` is updated to incorporate this check before saving a bib, enhancing user interaction with confirmation dialogs for duplicate assignments. Additionally, new functions are added in `inc_fx_inscriptions_gestion.php` to manage duplicate policies and retrieve existing participants with the same bib number, improving data integrity and user experience in the registration management interface.
This commit is contained in:
@ -107,6 +107,49 @@ switch ($strAction) {
|
|||||||
$tabRetour = array('state' => 'ok', 'html' => $strForm);
|
$tabRetour = array('state' => 'ok', 'html' => $strForm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'bib_duplicate_check':
|
||||||
|
// Controle "dossard en double" dans l'evenement (avant enregistrement legacy).
|
||||||
|
// Ne modifie rien : renvoie qui porte deja ce dossard + la politique a appliquer.
|
||||||
|
$intParId = intval($_REQUEST['par_id'] ?? 0);
|
||||||
|
$strNoBib = trim((string)($_REQUEST['no_bib'] ?? ''));
|
||||||
|
$blnTeam = (trim((string)($_REQUEST['type'] ?? '')) === 'no_equipe');
|
||||||
|
|
||||||
|
$intEveId = fxEveAccesResolveEveIdFromParId($intParId);
|
||||||
|
if ($intEveId <= 0 || !fxInscrGestionCanDo($intComId, $intEveId, 'inscriptions_gestion.bib_edit')) {
|
||||||
|
$tabRetour = array('state' => 'error', 'message' => 'unauthorized');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$strPolicy = fxInscrGestionBibDuplicatePolicy($intEveId);
|
||||||
|
|
||||||
|
if ($strNoBib === '') {
|
||||||
|
$tabRetour = array('state' => 'ok', 'duplicate' => false, 'policy' => $strPolicy, 'who' => array());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commande courante a exclure du controle (un participant ne se "double" pas lui-meme).
|
||||||
|
$intPecOrig = intval($objDatabase->fxGetVar(
|
||||||
|
'SELECT e.pec_id_original FROM resultats_epreuves_commandees e, resultats_participants p'
|
||||||
|
. ' WHERE p.par_id = ' . $intParId . ' AND p.pec_id = e.pec_id_original LIMIT 1'
|
||||||
|
));
|
||||||
|
|
||||||
|
$arrDup = fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intPecOrig, $blnTeam);
|
||||||
|
$arrWho = array();
|
||||||
|
foreach ($arrDup as $rowDup) {
|
||||||
|
$arrWho[] = array(
|
||||||
|
'name' => fxInscrGestionEsc(fxUnescape($rowDup['par_nom']) . ', ' . fxUnescape($rowDup['par_prenom'])),
|
||||||
|
'epreuve' => fxInscrGestionEsc(fxInscrGestionEpreuveLabel($rowDup['epr_id'], $strLangue)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tabRetour = array(
|
||||||
|
'state' => 'ok',
|
||||||
|
'duplicate' => count($arrWho) > 0,
|
||||||
|
'policy' => $strPolicy,
|
||||||
|
'who' => $arrWho,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'transaction_resume':
|
case 'transaction_resume':
|
||||||
// Resume de la transaction (meme rendu que facture.php cote promoteur), affichable
|
// Resume de la transaction (meme rendu que facture.php cote promoteur), affichable
|
||||||
// a tout moment depuis la barre Gestion via un panneau repliable independant.
|
// a tout moment depuis la barre Gestion via un panneau repliable independant.
|
||||||
|
|||||||
@ -1069,49 +1069,61 @@ if ($strLangue == 'fr') {
|
|||||||
str_new_no_bib = $("#txt_no_bib_e" + int_par_id).val();
|
str_new_no_bib = $("#txt_no_bib_e" + int_par_id).val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*bootbox.confirm({
|
(function (action, parId, pecId, eveId, eprId, newBib) {
|
||||||
title: "<?php afficheTexte('confirm-title', 1, 1, 1); ?>",
|
// Enregistrement reel du dossard (chemin legacy promoteur, inchange).
|
||||||
message: "<?php afficheTexte('promoteur_bib_manual'); ?>",
|
function saveBib() {
|
||||||
buttons: {
|
$preloader_text.html('<?php afficheTexte('preloader_wait', 1, 0, 1); ?>');
|
||||||
confirm: {
|
$preloader.show();
|
||||||
label: '<?php afficheTexte('confirm-btn-confirm', 1, 1, 1); ?>',
|
$.post('<?php echo $vDomaine; ?>/ajax_promoteur.php', 'a=' + action + '&eve_id=' + eveId + '&new_no_bib=' + newBib + '&pec_id=' + pecId + '&epr_id=' + eprId + '&par_id=' + parId + '&lang=<?php echo $strLangue; ?>', function ($result) {
|
||||||
className: 'btn btn-success rounded-0'
|
// Succes : rien a afficher pour l'instant.
|
||||||
},
|
}, 'json');
|
||||||
cancel: {
|
$preloader.fadeOut('slow');
|
||||||
label: '<?php afficheTexte('confirm-btn-cancel', 1, 1, 1); ?>',
|
|
||||||
className: 'btn btn-danger rounded-0'
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
callback: function (result) {
|
|
||||||
if (result === true) {*/
|
|
||||||
$preloader_text.html('<?php afficheTexte('preloader_wait', 1, 0, 1); ?>');
|
|
||||||
$preloader.show();
|
|
||||||
|
|
||||||
$.post('<?php echo $vDomaine; ?>/ajax_promoteur.php', 'a=' + str_action + '&eve_id=' + int_eve_id + '&new_no_bib=' + str_new_no_bib + '&pec_id=' + int_pec_id + '&epr_id=' + int_epr_id + '&par_id=' + int_par_id + '&lang=<?php echo $strLangue; ?>', function ($result) {
|
var bibTrim = (newBib == null ? '' : ('' + newBib)).trim();
|
||||||
|
// Suppression d'un dossard (champ vide) : aucun controle de doublon.
|
||||||
|
if (bibTrim === '') { saveBib(); return; }
|
||||||
|
|
||||||
if ($result.state == 'success') {
|
// Garde-fou "dossard en double" dans l'evenement. La politique
|
||||||
/*bootbox.alert({
|
// (warn / block / allow) est decidee cote serveur — par evenement a terme.
|
||||||
title: "<?php afficheTexte('alert-title', 1, 1, 1); ?>",
|
$.post('<?php echo $vDomaine; ?>/ajax_inscr_gestion.php', {
|
||||||
message: "<?php afficheTexte('promoteur_bib_manuel'); ?>",
|
a: 'bib_duplicate_check',
|
||||||
buttons: {
|
par_id: parId,
|
||||||
ok: {
|
no_bib: bibTrim,
|
||||||
label: '<?php afficheTexte('alert-btn-ok', 1, 1, 1); ?>',
|
type: action,
|
||||||
className: 'btn btn-primary rounded-0'
|
lang: '<?php echo $strLangue; ?>'
|
||||||
}
|
}, function (chk) {
|
||||||
},
|
if (!chk || chk.state !== 'ok' || !chk.duplicate) { saveBib(); return; }
|
||||||
callback: function (result) {
|
|
||||||
if (result === true) {
|
|
||||||
|
|
||||||
}
|
var lignes = (chk.who || []).map(function (w) {
|
||||||
}
|
return '<li><strong>' + w.name + '</strong>' + (w.epreuve ? ' — ' + w.epreuve : '') + '</li>';
|
||||||
});*/
|
}).join('');
|
||||||
}
|
|
||||||
}, 'json');
|
|
||||||
|
|
||||||
$preloader.fadeOut('slow');
|
// Politique bloquante (prevue pour le futur) : interdiction pure.
|
||||||
/*}
|
if (chk.policy === 'block') {
|
||||||
}
|
bootbox.alert({
|
||||||
});*/
|
title: "<?php if ($strLangue == 'fr') { ?>Dossard déjà utilisé<?php } else { ?>Bib already used<?php } ?>",
|
||||||
|
message: "<?php if ($strLangue == 'fr') { ?>Ce dossard est déjà assigné à :<?php } else { ?>This bib is already assigned to:<?php } ?><ul style=\"margin:8px 0;\">" + lignes + "</ul><?php if ($strLangue == 'fr') { ?>Les doublons sont interdits pour cet événement.<?php } else { ?>Duplicates are not allowed for this event.<?php } ?>",
|
||||||
|
buttons: { ok: { label: '<?php afficheTexte('alert-btn-ok', 1, 1, 1); ?>', className: 'btn btn-primary rounded-0' } }
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Politique d'avertissement (defaut actuel) : confirmation du doublon.
|
||||||
|
bootbox.confirm({
|
||||||
|
title: "<?php if ($strLangue == 'fr') { ?>Dossard en double<?php } else { ?>Duplicate bib<?php } ?>",
|
||||||
|
message: "<?php if ($strLangue == 'fr') { ?>Ce dossard est déjà assigné à :<?php } else { ?>This bib is already assigned to:<?php } ?><ul style=\"margin:8px 0;\">" + lignes + "</ul><?php if ($strLangue == 'fr') { ?>Voulez-vous vraiment assigner ce dossard en double ?<?php } else { ?>Do you really want to assign this bib as a duplicate?<?php } ?>",
|
||||||
|
buttons: {
|
||||||
|
confirm: { label: '<?php if ($strLangue == 'fr') { ?>Assigner quand même<?php } else { ?>Assign anyway<?php } ?>', className: 'btn btn-warning rounded-0' },
|
||||||
|
cancel: { label: '<?php afficheTexte('confirm-btn-cancel', 1, 1, 1); ?>', className: 'btn btn-secondary rounded-0' }
|
||||||
|
},
|
||||||
|
callback: function (result) { if (result === true) { saveBib(); } }
|
||||||
|
});
|
||||||
|
}, 'json').fail(function () {
|
||||||
|
// Echec du controle : on n'empeche pas l'enregistrement (mode non bloquant).
|
||||||
|
saveBib();
|
||||||
|
});
|
||||||
|
})(str_action, int_par_id, int_pec_id, int_eve_id, int_epr_id, str_new_no_bib);
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
$("#row_action_" + int_epr_id).val('defaut');
|
$("#row_action_" + int_epr_id).val('defaut');
|
||||||
|
|||||||
@ -541,6 +541,52 @@ function fxInscrGestionFetchRowByPec($intPecId, $intEveId) {
|
|||||||
return $objDatabase->fxGetRow($sql);
|
return $objDatabase->fxGetRow($sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Politique de gestion des dossards en double pour un evenement.
|
||||||
|
* Pour l'instant : toujours 'warn' (avertissement non bloquant).
|
||||||
|
*
|
||||||
|
* Hook prevu pour le futur : lire un reglage par evenement afin de renvoyer
|
||||||
|
* 'block' (interdiction totale) ou 'allow' (doublons silencieux). Exemple :
|
||||||
|
* $rec = fxGetEvenementsId($intEveId);
|
||||||
|
* if (!empty($rec['eve_bib_doublon_interdit'])) return 'block';
|
||||||
|
* if (!empty($rec['eve_bib_doublon_autorise'])) return 'allow';
|
||||||
|
*
|
||||||
|
* @return string 'warn' | 'block' | 'allow'
|
||||||
|
*/
|
||||||
|
function fxInscrGestionBibDuplicatePolicy($intEveId) {
|
||||||
|
return 'warn';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Participants d'un evenement deja porteurs du dossard donne (hors la commande
|
||||||
|
* courante). Alimente le garde-fou "dossard en double".
|
||||||
|
*
|
||||||
|
* @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) {
|
||||||
|
global $objDatabase;
|
||||||
|
|
||||||
|
$strNoBib = trim((string)$strNoBib);
|
||||||
|
if (intval($intEveId) <= 0 || $strNoBib === '') {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$strBibCol = $blnTeam ? 'e.no_equipe' : 'p.no_bib';
|
||||||
|
$sql = 'SELECT p.par_nom, p.par_prenom, e.epr_id'
|
||||||
|
. ' FROM resultats_epreuves_commandees e, resultats_participants p'
|
||||||
|
. ' WHERE e.eve_id = ' . intval($intEveId)
|
||||||
|
. ' AND p.pec_id = e.pec_id_original'
|
||||||
|
. ' AND e.is_cancelled = 0 AND e.pec_actif = 1'
|
||||||
|
. " AND TRIM(" . $strBibCol . ") = '" . $objDatabase->fxEscape($strNoBib) . "'"
|
||||||
|
. ' AND e.pec_id_original <> ' . intval($intExceptPec)
|
||||||
|
. ' GROUP BY e.pec_id_original'
|
||||||
|
. ' ORDER BY p.par_nom, p.par_prenom';
|
||||||
|
|
||||||
|
$tab = $objDatabase->fxGetResults($sql);
|
||||||
|
return is_array($tab) ? $tab : array();
|
||||||
|
}
|
||||||
|
|
||||||
function fxInscrGestionEpreuveLabel($intEprId, $strLangue) {
|
function fxInscrGestionEpreuveLabel($intEprId, $strLangue) {
|
||||||
$tab = fxGetEpreuve($intEprId);
|
$tab = fxGetEpreuve($intEprId);
|
||||||
if ($tab === null) {
|
if ($tab === null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user