Implement reset all apply functionality for epreuve and update version code to 4.72.747

This commit introduces a new action, `reset_all_apply`, in the AJAX handler to reset all bib numbers for participants in a specified epreuve. It includes validation for locked ranges and updates the database accordingly. Additionally, new CSS styles are added for the reset button, and JavaScript functions are implemented to manage the button's state based on participant conditions. The version code is incremented to reflect these changes.
This commit is contained in:
2026-07-08 09:57:49 -04:00
parent 4cf2ef98d0
commit c2972aa015
6 changed files with 296 additions and 1 deletions

View File

@ -34,6 +34,7 @@ $arrBibAjaxActions = [
'batch_apply_chunk',
'reset_preview',
'reset_apply',
'reset_all_apply',
'save_team_mode',
'toggle_lock',
'save_auto_config',
@ -905,6 +906,72 @@ if ($action == 'reset_apply') {
exit;
}
// =====================
// RESET ALL ÉPREUVE
// =====================
if ($action == 'reset_all_apply') {
$epr_id = intval($_POST['epr_id'] ?? 0);
if ($epr_id <= 0) {
echo json_encode([
'success' => false,
'message' => fxBibMsg('bib_v4_ajax_params_invalid'),
]);
exit;
}
$lockCheck = fxBibAssertEpreuveNoLockedRanges($epr_id);
if (!$lockCheck['success']) {
echo json_encode([
'success' => false,
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_js_reset_all_locked'),
]);
exit;
}
$participants = fxGetParticipantsForEpreuveResetAll($epr_id);
$count = 0;
foreach ($participants as $p) {
$par_id = intval($p['par_id']);
if ($par_id <= 0) {
continue;
}
$sql = "
UPDATE resultats_participants
SET no_bib = NULL
WHERE par_id = $par_id
AND is_cancelled = 0
";
$objDatabase->fxQuery($sql);
$count++;
}
$html = renderBibView(
$epr_id,
0,
$strLangue,
'reset',
$participants,
fxBibTexte('bib_v4_ajax_title_reset_all_done'),
fxBibMsg('bib_v4_ajax_reset_done_count', $count),
'success'
);
echo json_encode([
'success' => true,
'html' => $html,
]);
exit;
}
// =====================
// SAVE TEAM MODE
// =====================
if ($action == 'save_team_mode') {

View File

@ -1288,6 +1288,22 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active {
margin-top:0;
}
/* MSIN-4436 — Réinitialisation totale, sous l'en-tête identité. */
.epr-identity-reset-all{
flex-shrink:0;
padding:6px 8px 8px;
background:#fff;
border-top:1px solid #e8edf5;
}
.epr-identity-reset-all .btn-reset-all-epr{
width:100%;
white-space:normal;
line-height:1.25;
font-size:11px;
padding:5px 8px;
}
.epr-col-right{
display:flex;
flex-direction:column;

View File

@ -1544,6 +1544,33 @@
});
}
function bibSyncResetAllEprButton(row) {
if (!row) {
return;
}
let wrap = row.querySelector('.epr-identity-reset-all');
if (!wrap) {
return;
}
let avecBib = parseInt(bibQuery(row, '.bib-avec')?.textContent || '0', 10) || 0;
if (avecBib <= 0) {
wrap.classList.add('bib-ui-hidden');
return;
}
wrap.classList.remove('bib-ui-hidden');
let btn = wrap.querySelector('.btn-reset-all-epr');
if (!btn) {
return;
}
let hasLock = row.querySelector('.btn-bib-lock--closed') !== null;
btn.disabled = hasLock;
}
function syncBibUiState(row) {
if (!row) return;
@ -1599,6 +1626,7 @@
bibSetVisible('.epr-batch-order-wrap', showBatchReady && !modes.reset, row);
bibSetVisible('.epr-action-sim-group', showBatchReady && !modes.reset, row);
bibSetVisible('.epr-action-go-group', showBatchReady, row);
bibSyncResetAllEprButton(row);
}
function updateBatchAnalysis(row) {
@ -1903,12 +1931,65 @@
if (data.html) {
setBibContainerHtml(row, data.html);
bibSyncResetAllEprButton(row);
}
});
return;
}
// =====================
// MSIN-4436 — Réinitialiser tous les dossards (épreuve entière)
// =====================
let btnResetAllEpr = e.target.closest('.btn-reset-all-epr');
if (btnResetAllEpr) {
e.preventDefault();
let row = btnResetAllEpr.closest('.epr-row');
if (!row) {
return;
}
if (btnResetAllEpr.disabled) {
alert(bibJsConfirm('jsResetAllLocked'));
return;
}
if (row.querySelector('.btn-bib-lock--closed')) {
alert(bibJsConfirm('jsResetAllLocked'));
bibSyncResetAllEprButton(row);
return;
}
if (!confirm(bibJsConfirm('jsResetAllConfirm'))) {
return;
}
bibFetch('/ajax_bib_range.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body:
'action=reset_all_apply'
+ '&epr_id=' + encodeURIComponent(row.dataset.eprId)
+ bibAjaxLangSuffix()
})
.then(res => res.json())
.then(data => {
if (!data.success) {
alert(data.message || bibJs('jsErrGeneric'));
return;
}
bibAfterBatchGoSuccess(row, data, false);
});
return;
}
// =====================
// DELETE
// =====================

View File

@ -2742,6 +2742,35 @@ function fxBibRequirePromoteurSession() {
return !empty($_SESSION['com_id']) || !empty($_SESSION['usa_id']);
}
/** MSIN-4436 — Au moins une séquence verrouillée sur l'épreuve. */
function fxBibEpreuveHasLockedRanges($epr_id) {
global $objDatabase;
$epr_id = (int)$epr_id;
if ($epr_id <= 0) {
return false;
}
$sql = "
SELECT COUNT(*)
FROM inscriptions_epreuves_bib
WHERE epr_id = $epr_id
AND epr_bib_locked = 1
";
return (int)$objDatabase->fxGetVar($sql) > 0;
}
/** MSIN-4436 — Réinitialisation totale : aucun cadenas sur l'épreuve. */
function fxBibAssertEpreuveNoLockedRanges($epr_id) {
if (fxBibEpreuveHasLockedRanges($epr_id)) {
return ['success' => false, 'message' => fxBibMsg('bib_v4_js_reset_all_locked')];
}
return ['success' => true];
}
/** Resout eve_id depuis la requete AJAX bib (eve_id direct ou via epr_id). */
function fxBibResolveEveIdFromRequest() {
global $objDatabase;
@ -3114,6 +3143,8 @@ function fxBibModuleJsDataAttrs() {
'batch-progress' => 'bib_v4_js_batch_progress',
'global-no-epr' => 'bib_v4_js_global_no_epr',
'global-no-seq' => 'bib_v4_js_global_no_seq',
'reset-all-confirm' => 'bib_v4_js_reset_all_confirm',
'reset-all-locked' => 'bib_v4_js_reset_all_locked',
'assign-full' => 'bib_v4_ajax_assign_full',
'assign-partial' => 'bib_v4_ajax_assign_partial',
'assign-none' => 'bib_v4_ajax_assign_none',
@ -3502,6 +3533,29 @@ function renderBibEpreuveIdentityHeader($tabEpreuve, $infoBib, $strLangue = 'fr'
return ob_get_clean();
}
/** MSIN-4436 — Réinitialiser tous les dossards de l'épreuve (sans sélection de séquences). */
function renderBibEpreuveResetAllButton($epr_id, $infoBib, $blnHasLockedRanges = false) {
if ((int)($infoBib['avec_bib'] ?? 0) <= 0) {
return '';
}
$strTipClef = $blnHasLockedRanges ? 'bib_v4_tip_reset_all_locked' : 'bib_v4_tip_reset_all';
ob_start();
?>
<div class="epr-identity-reset-all">
<button type="button"
class="btn btn-sm btn-danger btn-reset-all-epr"
data-epr-id="<?php echo (int)$epr_id; ?>"
<?php echo $blnHasLockedRanges ? ' disabled' : ''; ?>
<?php echo fxBibTippyAttr($strTipClef); ?>>
<?php fxBibTexte('bib_v4_reset_all', 1); ?>
</button>
</div>
<?php
return ob_get_clean();
}
/** Bouton réduire / développer le corps du bloc (en-tête reste visible). */
function fxBibBlockCollapseToggle($strLangue = 'fr', $blnCollapsed = true) {
$strCollapse = fxBibTexte('bib_v4_collapse', 0);
@ -4131,6 +4185,7 @@ function fxShowBibTool4($str_code, $int_eve_id, $strLangue){
// MSIN-4379 — Étape 2 : détecte si l'auto est actif (au moins une séquence epr_bib_auto=1).
// Prochain tour : étape 67 (assignation à l'achat).
$blnAutoActive = fxIsBibAutoActive((int)$tabEpreuves[$i]['epr_id']);
$blnHasLockedRanges = fxBibEpreuveHasLockedRanges((int)$tabEpreuves[$i]['epr_id']);
?>
@ -4149,6 +4204,7 @@ function fxShowBibTool4($str_code, $int_eve_id, $strLangue){
<!-- GAUCHE — identité épreuve (titre dans la bande bleue, cohérent avec la droite) -->
<div class="epr-block epr-block-identity">
<?php echo renderBibEpreuveIdentityHeader($tabEpreuves[$i], $infoBib, $strLangue); ?>
<?php echo renderBibEpreuveResetAllButton((int)$tabEpreuves[$i]['epr_id'], $infoBib, $blnHasLockedRanges); ?>
<?php if ((int)$tabEpreuves[$i]['epr_equipe'] === 1) { ?>
<div class="epr-content epr-content--identity">
<?php
@ -6591,6 +6647,31 @@ function fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id =
'nb_manque' => $nbManque
];
}
/** MSIN-4436 — Tous les participants avec dossard sur l'épreuve (y compris hors séquences). */
function fxGetParticipantsForEpreuveResetAll($epr_id) {
global $objDatabase;
$epr_id = (int)$epr_id;
if ($epr_id <= 0) {
return [];
}
$sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib');
$sql = "
SELECT p.*
FROM resultats_participants p
WHERE p.epr_id = $epr_id
AND p.is_cancelled = 0
AND p.no_bib IS NOT NULL
AND p.no_bib > 0
ORDER BY $sqlBibNumP
";
return $objDatabase->fxGetResults($sql);
}
function fxGetParticipantsForBatchReset($epr_id, $ranges) {
global $objDatabase;

View File

@ -7,7 +7,7 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.745');
define('_VERSION_CODE', '4.72.747');
define('_DATE_CODE', '2026-07-08');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');

View File

@ -0,0 +1,50 @@
-- MSIN-4436 — Réinitialiser tous les dossards d'une épreuve
-- Idempotent. Exécuter après déploiement PHP/JS.
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_reset_all', 'fr', 'Réinitialiser tous les dossards', 'Retire tous les numéros assignés sur cette épreuve, y compris les dossards saisis manuellement. Aucune sélection de séquence requise.', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_reset_all' AND info_langue = 'fr' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_reset_all', 'en', 'Reset all bibs', 'Removes every assigned bib on this race, including manually entered numbers. No sequence selection required.', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_reset_all' AND info_langue = 'en' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_tip_reset_all', 'fr', 'Retire tous les dossards de l''épreuve (assignation batch, auto et manuelle).', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_tip_reset_all' AND info_langue = 'fr' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_tip_reset_all', 'en', 'Removes all bibs on this race (batch, auto, and manual).', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_tip_reset_all' AND info_langue = 'en' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_tip_reset_all_locked', 'fr', 'Déverrouillez toutes les séquences (cadenas) avant de réinitialiser.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_tip_reset_all_locked' AND info_langue = 'fr' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_tip_reset_all_locked', 'en', 'Unlock all sequences (padlocks) before resetting.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_tip_reset_all_locked' AND info_langue = 'en' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_js_reset_all_confirm', 'fr', 'Attention : tous les dossards de cette épreuve seront retirés.\n\nCela inclut les dossards assignés manuellement, en lot ou automatiquement.\n\nCette action est irréversible. Continuer ?', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_reset_all_confirm' AND info_langue = 'fr' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_js_reset_all_confirm', 'en', 'Warning: all bibs on this race will be removed.\n\nThis includes manually assigned, batch, and automatic bibs.\n\nThis cannot be undone. Continue?', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_reset_all_confirm' AND info_langue = 'en' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_js_reset_all_locked', 'fr', 'Impossible : au moins une séquence est verrouillée.\n\nDéverrouillez tous les cadenas à droite avant de réinitialiser tous les dossards.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_reset_all_locked' AND info_langue = 'fr' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_js_reset_all_locked', 'en', 'Cannot proceed: at least one sequence is locked.\n\nUnlock all padlocks on the right before resetting all bibs.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_reset_all_locked' AND info_langue = 'en' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_ajax_title_reset_all_done', 'fr', 'Réinitialisation totale terminée', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_ajax_title_reset_all_done' AND info_langue = 'fr' AND info_prg = 'compte.php');
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
SELECT 'bib_v4_ajax_title_reset_all_done', 'en', 'Full reset completed', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_ajax_title_reset_all_done' AND info_langue = 'en' AND info_prg = 'compte.php');