1) { // calculer le début et la fin de la boucle $intStart = ($intPage - 1) * $intNbItemsParPage + 1; $intEnd = $intStart + $intNbItemsParPage - 1; } if ($blnDon) { $strPrenom = 'rech_prenom_don'; $strNom = 'rech_nom_don'; $strEquipe = 'rech_equipe_don'; } else { $strPrenom = 'rech_prenom'; $strNom = 'rech_nom'; $strEquipe = 'rech_equipe'; } $strRechercheForm .= ' '; if ($blnDon) { $strWhere2 = " a.eve_id = " . intval($intEveId) . " AND a.sta_id = 3 AND a.no_panier = d.no_panier AND e.pec_id_original = d.pec_id "; $strWhere = '1 = 1'; if ($strRechercheNom != '') $strWhere .= ' AND com_nom LIKE "%' . $strRechercheNom . '%"'; if ($strRecherchePrenom != '') $strWhere .= ' AND com_prenom LIKE "%' . $strRecherchePrenom . '%"'; if ($strNomParticipant!= '') $strWhere .= ' AND par_nom LIKE "%' . $strNomParticipant. '%"'; if ($strPrenomParticipant != '') $strWhere .= ' AND par_prenom LIKE "%' . $strPrenomParticipant. '%"'; if ($strNoCommande != '') $strWhere .= ' AND no_commande LIKE "%' . $objDatabase->fxEscape($strNoCommande) . '%"'; if ($strNomEquipe != '') $strWhere .= ' AND pec_nom_equipe LIKE "%' . $objDatabase->fxEscape($strNomEquipe) . '%"'; $sqlTableTemp = "CREATE TEMPORARY TABLE dons_temp AS (SELECT a.com_nom, a.com_prenom, a.eve_id, a.no_panier, a.no_commande, d.pd_montant, d.pd_recu, d.pd_recu_pdf, d.pd_recu_numero, d.pec_id, d.par_id, e.pec_nom_equipe, e.pec_equipe, e.epr_id, IF(d.par_id <> 0, (SELECT p.par_nom FROM resultats_participants p WHERE d.par_id = p.par_id_original), '') AS par_nom, IF(d.par_id <> 0, (SELECT p.par_prenom FROM resultats_participants p WHERE d.par_id = p.par_id_original), '') AS par_prenom FROM inscriptions_panier_acheteurs a, resultats_epreuves_commandees e, inscriptions_panier_dons d WHERE " . $strWhere2 . ")"; $qryTableTemp = $objDatabase->fxQuery($sqlTableTemp); $sqlInscriptionsParPage = "SELECT * FROM dons_temp WHERE " . $strWhere; $tabInscriptionsParPage = $objDatabase->fxGetResults($sqlInscriptionsParPage); $sqlDelete = "DROP TABLE IF EXISTS dons_temp"; $qryDelete = $objDatabase->fxQuery($sqlDelete); } else { $strWhere = ' e.eve_id = ' . intval($intEveId); //MSIN-4009 //$strWhere .= ' AND e.pec_actif = 1'; // MSIN-3524 if ($strRechercheNom != '') { $strWhere .= ' AND p.par_nom LIKE "%' . $strRechercheNom . '%"'; } if ($strRecherchePrenom != '') { $strWhere .= ' AND p.par_prenom LIKE "%' . $strRecherchePrenom . '%"'; } if ($strNoCommande != '') { $strWhere .= ' AND p.no_commande LIKE "%' . $objDatabase->fxEscape($strNoCommande) . '%"'; } if ($strNomEquipe != '') { $strWhere .= ' AND p.par_nom_equipe LIKE "%' . $objDatabase->fxEscape($strNomEquipe) . '%"'; } if ($intEpreuve != 0) { $strWhere .= " AND p.epr_id = " . intval($intEpreuve) . " AND p.epr_id = e.epr_id"; } if (intval($chk_bib) == 1) { $strWhere .= " AND TRIM(p.no_bib) = ''"; } if (intval($chk_cancelled) == 1) { $strWhere .= ' AND e.is_cancelled IN(0,1)'; // MSIN-3522 } else { $strWhere .= ' AND e.is_cancelled = 0 AND e.pec_actif = 1'; // MSIN-3522 } $sqlInscriptionsParPage = 'select p.no_bib,p.no_bib_remis,p.no_bib_remis_date,p.no_bib_remis_par, p.par_id, p.par_equipe, p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, e.pec_actif, p.rol_id, e.no_commande, e.no_panier, e.no_equipe, e.pec_equipe from resultats_epreuves_commandees e, resultats_participants p where ' . $strWhere . ' and p.pec_id = e.pec_id_original group by e.pec_id_original'; $tabInscriptionsParPage = $objDatabase->fxGetResults($sqlInscriptionsParPage); } if ($tabInscriptionsParPage != null) { $arrColonnes = fxGetchampsPromoteur($blnDon, $strLangue); $strRechercheResultats .= '

' . afficheTexte('promoteur_liste_inscrits', 0) . '

'; foreach ($arrColonnes as $intIndex => $arrValues) { $strRechercheResultats .= ' '; } $strRechercheResultats .= ' '; $intNbInscriptions = count($tabInscriptionsParPage); if ($intEnd > $intNbInscriptions) { $intEnd = $intNbInscriptions; } for ($j = $intStart; $j <= $intEnd; $j++) { $tabEpreuve = fxGetEpreuve($tabInscriptionsParPage[$j]['epr_id']); $strClasse = ($j & 1) ? '' : 'table-secondary'; if ($tabInscriptionsParPage[$j]['is_cancelled'] == '1') { $strClasse .= ' table-danger'; } $strRechercheResultats .= ' '; $strRechercheResultats .= fxShowColumnPromoteur($arrColonnes, $tabInscriptionsParPage, $j, $strLangue, $tabInscriptionsParPage[$j]['pec_equipe'],$abonnement); $strRechercheResultats .= ' '; } $intNbPagesTotal = ceil($intNbInscriptions / $intNbItemsParPage); // calculer le nb de pages $intNbItemsAffiches = $intEnd - ($intStart - 1); if ($strLangue == 'fr') { $strStatut = $intNbItemsAffiches . ' de ' . $intNbInscriptions . '
page ' . $intPage . ' de ' . $intNbPagesTotal; } else { $strStatut = $intNbItemsAffiches . ' of ' . $intNbInscriptions . '
page ' . $intPage . ' of ' . $intNbPagesTotal; } $strRechercheResultats .= '
' . fxUnescape($arrValues['label_' . $strLangue]) . '
' . $strStatut . '
'; // afficher pagination $tabQuery = $_GET; unset($tabQuery['pg']); unset($tabQuery['code']); unset($tabQuery['lang']); $strQuery = http_build_query($tabQuery, '', '&'); $strRecherchePagination = fxGetPagination($vDomaine . '/' . $str_code . '?' . $strQuery, $intNbInscriptions, $intNbItemsParPage, $intPage); } else { $strRechercheResultats = ' '; } $strDisplay = (!isset($_GET['pg']) && !isset($_GET['btn_recherche'])) ? '' : ' show'; $strIcon = "'" . $vDomaine . "/images/search-icon.png'"; $strRetour .= '

' . afficheTexte('txt_recherche', 0) . '

' . $strRechercheForm . '
' . $strRechercheResultats . ' ' . $strRecherchePagination . '
'; return $strRetour; } function fxShowRechercheinscription($str_code, $int_promoteur_id, $blnDon, $strLangue, $intEveId,$abonnement=0) { global $objDatabase, $vDomaine; $strRechercheForm = $strRechercheResultats = $strRetour = $strSelected = $strRecherchePrenom = $strRechercheNom = $strNoCommande = $strNomParticipant = $strNomEquipe = $strPrenomParticipant = $strRecherchePagination = $chk_bib = ''; $intEpreuve = 0; $intPage = $intStart = 1; $intNbItemsParPage = $intEnd = 100; // si apres recherche if (isset($_GET['rech_prenom'])) { $strRecherchePrenom = $_GET['rech_prenom']; } if (isset($_GET['rech_nom'])) { $strRechercheNom = $_GET['rech_nom']; } if (isset($_GET['rech_no_commande'])) { $strNoCommande = $_GET['rech_no_commande']; } if (isset($_GET['rech_nom_equipe'])) { $strNomEquipe = $_GET['rech_nom_equipe']; } if (isset($_GET['rech_nom_participant'])) { $strNomParticipant = $_GET['rech_nom_participant']; } if (isset($_GET['rech_prenom_participant'])) { $strPrenomParticipant = $_GET['rech_prenom_participant']; } if (isset($_GET['sel_rech_epreuve'])) { $intEpreuve = base64_decode(urldecode($_GET['sel_rech_epreuve'])); } if (isset($_GET['chk_bib'])) { $chk_bib = 1; } if (isset($_GET['chk_cancelled'])) { $chk_cancelled = 1; }else{ $chk_cancelled = 0;} if (isset($_GET['pg'])) { $intPage = $_GET['pg']; } if (intval($intPage) > 1) { // calculer le début et la fin de la boucle $intStart = ($intPage - 1) * $intNbItemsParPage + 1; $intEnd = $intStart + $intNbItemsParPage - 1; } if ($blnDon) { $strPrenom = 'rech_prenom_don'; $strNom = 'rech_nom_don'; $strEquipe = 'rech_equipe_don'; } else { $strPrenom = 'rech_prenom'; $strNom = 'rech_nom'; $strEquipe = 'rech_equipe'; } $strRechercheForm .= ' '; if ($blnDon) { $strWhere2 = " a.eve_id = " . intval($intEveId) . " AND a.sta_id = 3 AND a.no_panier = d.no_panier AND e.pec_id_original = d.pec_id "; $strWhere = '1 = 1'; if ($strRechercheNom != '') $strWhere .= ' AND com_nom LIKE "%' . $strRechercheNom . '%"'; if ($strRecherchePrenom != '') $strWhere .= ' AND com_prenom LIKE "%' . $strRecherchePrenom . '%"'; if ($strNomParticipant!= '') $strWhere .= ' AND par_nom LIKE "%' . $strNomParticipant. '%"'; if ($strPrenomParticipant != '') $strWhere .= ' AND par_prenom LIKE "%' . $strPrenomParticipant. '%"'; if ($strNoCommande != '') $strWhere .= ' AND no_commande LIKE "%' . $objDatabase->fxEscape($strNoCommande) . '%"'; if ($strNomEquipe != '') $strWhere .= ' AND pec_nom_equipe LIKE "%' . $objDatabase->fxEscape($strNomEquipe) . '%"'; $sqlTableTemp = "CREATE TEMPORARY TABLE dons_temp AS (SELECT a.com_nom, a.com_prenom, a.eve_id, a.no_panier, a.no_commande, d.pd_montant, d.pd_recu, d.pd_recu_pdf, d.pd_recu_numero, d.pec_id, d.par_id, e.pec_nom_equipe, e.pec_equipe, e.epr_id, IF(d.par_id <> 0, (SELECT p.par_nom FROM resultats_participants p WHERE d.par_id = p.par_id_original), '') AS par_nom, IF(d.par_id <> 0, (SELECT p.par_prenom FROM resultats_participants p WHERE d.par_id = p.par_id_original), '') AS par_prenom FROM inscriptions_panier_acheteurs a, resultats_epreuves_commandees e, inscriptions_panier_dons d WHERE " . $strWhere2 . ")"; $qryTableTemp = $objDatabase->fxQuery($sqlTableTemp); $sqlInscriptionsParPage = "SELECT * FROM dons_temp WHERE " . $strWhere; $tabInscriptionsParPage = $objDatabase->fxGetResults($sqlInscriptionsParPage); $sqlDelete = "DROP TABLE IF EXISTS dons_temp"; $qryDelete = $objDatabase->fxQuery($sqlDelete); } else { $strWhere = ' e.eve_id = ' . intval($intEveId); //$strWhere .= ' AND e.pec_actif = 1'; // MSIN-3524 if ($strRechercheNom != '') { $strWhere .= ' AND p.par_nom LIKE "%' . $strRechercheNom . '%"'; } if ($strRecherchePrenom != '') { $strWhere .= ' AND p.par_prenom LIKE "%' . $strRecherchePrenom . '%"'; } if ($strNoCommande != '') { $strWhere .= ' AND p.no_commande LIKE "%' . $objDatabase->fxEscape($strNoCommande) . '%"'; } if ($strNomEquipe != '') { $strWhere .= ' AND p.par_nom_equipe LIKE "%' . $objDatabase->fxEscape($strNomEquipe) . '%"'; } if ($intEpreuve != 0) { $strWhere .= " AND p.epr_id = " . intval($intEpreuve) . " AND p.epr_id = e.epr_id"; } if (intval($chk_bib) == 1) { $strWhere .= " AND TRIM(p.no_bib) = ''"; } if (intval($chk_cancelled) == 1) { $strWhere .= ' AND e.is_cancelled = 1'; // MSIN-3522 //MSIN-4010 } else { $strWhere .= ' AND e.is_cancelled = 0 AND e.pec_actif = 1'; // MSIN-3522 } $sqlInscriptionsParPage = 'select p.no_bib,p.no_bib_remis,p.no_bib_remis_date,p.no_bib_remis_par, p.par_id, p.par_equipe, p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, e.pec_actif, p.rol_id, e.no_commande, e.no_panier, e.no_equipe, e.pec_equipe from resultats_epreuves_commandees e, resultats_participants p where ' . $strWhere . ' and p.pec_id = e.pec_id_original group by e.pec_id_original'; $tabInscriptionsParPage = $objDatabase->fxGetResults($sqlInscriptionsParPage); } if ($tabInscriptionsParPage != null) { $arrColonnes = fxGetchampsPromoteur($blnDon, $strLangue); $strRechercheResultats .= '

' . afficheTexte('promoteur_liste_inscrits', 0) . '

'; foreach ($arrColonnes as $intIndex => $arrValues) { $strRechercheResultats .= ' '; } $strRechercheResultats .= ' '; $intNbInscriptions = count($tabInscriptionsParPage); if ($intEnd > $intNbInscriptions) { $intEnd = $intNbInscriptions; } for ($j = $intStart; $j <= $intEnd; $j++) { $tabEpreuve = fxGetEpreuve($tabInscriptionsParPage[$j]['epr_id']); $strClasse = ($j & 1) ? '' : 'table-secondary'; if ($tabInscriptionsParPage[$j]['is_cancelled'] == '1') { $strClasse .= ' table-danger'; } $strRechercheResultats .= ' '; $strRechercheResultats .= fxShowColumnPromoteur($arrColonnes, $tabInscriptionsParPage, $j, $strLangue, $tabInscriptionsParPage[$j]['pec_equipe'],$abonnement); $strRechercheResultats .= ' '; } $intNbPagesTotal = ceil($intNbInscriptions / $intNbItemsParPage); // calculer le nb de pages $intNbItemsAffiches = $intEnd - ($intStart - 1); if ($strLangue == 'fr') { $strStatut = $intNbItemsAffiches . ' de ' . $intNbInscriptions . '
page ' . $intPage . ' de ' . $intNbPagesTotal; } else { $strStatut = $intNbItemsAffiches . ' of ' . $intNbInscriptions . '
page ' . $intPage . ' of ' . $intNbPagesTotal; } $strRechercheResultats .= '
' . fxUnescape($arrValues['label_' . $strLangue]) . '
' . $strStatut . '
'; // afficher pagination $tabQuery = $_GET; unset($tabQuery['pg']); unset($tabQuery['code']); unset($tabQuery['lang']); $strQuery = http_build_query($tabQuery, '', '&'); $strRecherchePagination = fxGetPagination($vDomaine . '/' . $str_code . '?' . $strQuery, $intNbInscriptions, $intNbItemsParPage, $intPage); } else { $strRechercheResultats = ' '; } $strDisplay = (!isset($_GET['pg']) && !isset($_GET['btn_recherche'])) ? '' : ' show'; $strIcon = "'" . $vDomaine . "/images/search-icon.png'"; $strRetour .= '

' . afficheTexte('txt_recherche', 0) . '

' . $strRechercheForm . '
' . $strRechercheResultats . ' ' . $strRecherchePagination . '
'; return $strRetour; } /*/* * param $int_eve_id : le no. de l'evenement de l'epreuve a ajuster. * param $strLangue : langue d'affichage * */ function fxShowQuantites($int_eve_id, $strLangue) { global $objDatabase, $vDomaine; $tabEvenement = fxGetEvenements(fxGetEvenementsUrl($int_eve_id), $strLangue); // MSIN-1328 $sqlEpreuves = "SELECT * FROM inscriptions_epreuves where eve_id = " . intval($int_eve_id) . " AND epr_actif = 1"; $tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves); ?>

"; } echo $tabEpreuve['epr_type_' . $strLangue]; if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') { echo "
" . $tabEpreuve['epr_nom_' . $strLangue]; } ?>
   
fxGetResults($sqlEpreuves); ?>

"; } echo $tabEpreuve['epr_type_' . $strLangue]; if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') { echo "
" . $tabEpreuve['epr_nom_' . $strLangue]; } ?>

0 ? $nbSurListe : '';?> 0 ? $nbSurListe : '';?>
   
fxGetResults($sqlEpreuves); ?>

recalculer les catégorie
fxGetResults($sqlRegles); if ($arrRegles){ ?> $value){ ?>
fxGetResults($sqlEpreuves); $sqlBibAssignments = "SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri"; $tabBibAssignments = $objDatabase->fxGetResults($sqlBibAssignments); ?>

bib_assignment?a=show_bib_dupes&eve_id=" target="_blank">
fxGetVar($sqlLastBib); } else $intBibFinish = ''; $sqlCommandees = "SELECT COUNT(*) FROM inscriptions_panier_epreuves_commandees e, inscriptions_panier_acheteurs a WHERE e.epr_id = " . intval($tabEpreuves[$i]['epr_id']) . " AND e.no_panier = a.no_panier AND a.sta_id = 3"; $intQteCommandees = $objDatabase->fxGetVar($sqlCommandees); $sqlInscriptions = 'select p.no_bib, p.par_id, p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, p.rol_id, e.no_commande, e.no_panier, e.no_equipe from resultats_epreuves_commandees e, resultats_participants p where p.is_cancelled = 0 AND p.epr_id = ' . intval($tabEpreuves[$i]['epr_id']) . ' AND p.epr_id = e.epr_id and p.pec_id = e.pec_id_original group by e.pec_id_original'; $tabInscriptions = $objDatabase->fxGetResults($sqlInscriptions); $intNbInscriptions = count($tabInscriptions); // nb bibs used $sqlCount = "SELECT count(*) FROM resultats_participants WHERE epr_id = " . intval($tabEpreuves[$i]['epr_id']) . " AND (no_bib <> '' AND no_bib <> 0)"; $intNbBibs = $objDatabase->fxGetVar($sqlCount); // new calcul de num_bibs_left if($tabEpreuves[$i]['epr_bib_finish'] == 0){ $intNbBibsLeft = ($intQteCommandees + $tabEpreuves[$i]['epr_qte']) - $intNbBibs; } else { $intNbBibsLeft = (($intBibStart + $intNbBibs) - $intBibStart) - $intNbBibs; } ?>

"; } echo $tabEpreuves[$i]['epr_type_' . $strLangue]; if (trim($tabEpreuves[$i]['epr_nom_' . $strLangue]) != '') { echo "
" . $tabEpreuves[$i]['epr_nom_' . $strLangue]; } ?>





fxGetResults($sqlEpreuves); $sqlBibAssignments = "SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri"; $tabBibAssignments = $objDatabase->fxGetResults($sqlBibAssignments); ?>

fxGetVar($sqlLastBib); } else $intBibFinish = ''; $sqlCommandees = "SELECT COUNT(*) FROM inscriptions_panier_epreuves_commandees e, inscriptions_panier_acheteurs a WHERE e.epr_id = " . intval($tabEpreuves[$i]['epr_id']) . " AND e.no_panier = a.no_panier AND a.sta_id = 3"; $intQteCommandees = $objDatabase->fxGetVar($sqlCommandees); $sqlInscriptions = 'select p.no_bib, p.par_id, p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, p.rol_id, e.no_commande, e.no_panier, e.no_equipe from resultats_epreuves_commandees e, resultats_participants p where p.is_cancelled = 0 AND p.epr_id = ' . intval($tabEpreuves[$i]['epr_id']) . ' AND p.epr_id = e.epr_id and p.pec_id = e.pec_id_original group by e.pec_id_original'; $tabInscriptions = $objDatabase->fxGetResults($sqlInscriptions); $intNbInscriptions = count($tabInscriptions); // nb bibs used $sqlCount = "SELECT count(*) FROM resultats_participants WHERE epr_id = " . intval($tabEpreuves[$i]['epr_id']) . " AND (no_bib <> '' AND no_bib <> 0)"; $intNbBibs = $objDatabase->fxGetVar($sqlCount); // new calcul de num_bibs_left if($tabEpreuves[$i]['epr_bib_finish'] == 0){ $intNbBibsLeft = ($intQteCommandees + $tabEpreuves[$i]['epr_qte']) - $intNbBibs; } else { $intNbBibsLeft = (($intBibStart + $intNbBibs) - $intBibStart) - $intNbBibs; } ?>

"; } echo $tabEpreuves[$i]['epr_type_' . $strLangue]; if (trim($tabEpreuves[$i]['epr_nom_' . $strLangue]) != '') { echo "
" . $tabEpreuves[$i]['epr_nom_' . $strLangue]; } ?>





fxGetVar($sql); } function fxShowBibNumber($str_bib, $int_epr_id, $type){ // enlever no. epr du no bib $str_return = str_replace($int_epr_id . "-", "", $str_bib); switch($type){ case 'equipe': break; case 'participant': $str_return = str_replace("-", "", $str_return); break; } return $str_return; } function fxShowRapports($tabRapports, $strLangue, $intEvenement) { global $vDomaine; $arrEvenement = fxGetEvenementsId($intEvenement); ?>

'' GROUP BY no_bib HAVING c > 1"; $tabNoBib = $objDatabase->fxGetResults($sqlNoBib); ?>

fxGetResults($sqlDupes); if ($tabDupes != null) { foreach ($tabDupes as $dupe) { $tabEpreuve = fxGetEpreuve($dupe['epr_id']); ?>
"; } echo $tabEpreuve['epr_type_' . $strLangue]; if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') { echo "
" . $tabEpreuve['epr_nom_' . $strLangue]; } echo " (" . $tabEpreuve['epr_id'] . ")"; ?>
fxQuery($sqlTri); $strOrderBy = ''; // set ORDER By switch($tab_epreuve['ba_id']){ case 1: $strOrderBy = " ORDER BY TRIM(p.par_prenom)"; break; case 2: $strOrderBy = " ORDER BY TRIM(p.par_nom), TRIM(p.par_prenom)"; break; case 3: $strOrderBy = " ORDER BY p.par_maj"; break; case 4: $strOrderBy = " ORDER BY p.par_naissance DESC"; break; } //get inscriptions $sqlInscriptions = "SELECT * FROM resultats_participants p WHERE p.is_cancelled = 0 AND p.epr_id = " . intval($tab_epreuve['epr_id']) . $strOrderBy; $tabInscriptions = $objDatabase->fxGetResults($sqlInscriptions); // get epreuves_commandees (pour les equipes) $sqlEpreuvesCommandees = "select * from resultats_epreuves_commandees c, resultats_participants p where c.epr_id = " . intval($tab_epreuve['epr_id']) . " and c.pec_actif = 1 and c.pec_id_original = p.pec_id GROUP BY pec_id_original" . $strOrderBy; $tabEpreuvesCommandees = $objDatabase->fxGetResults($sqlEpreuvesCommandees); ?>


"> ">
"; if ($tab_epreuve['epr_type_' . $strLangue] != '') echo $tab_epreuve['epr_type_' . $strLangue]; echo " (" . $tab_epreuve['epr_id'] . ")"; ?>
"; if ($tab_epreuve['epr_type_' . $strLangue] != '') echo $tab_epreuve['epr_type_' . $strLangue]; echo " (" . $tab_epreuve['epr_id'] . ")"; ?>
    fxGetResults($sqlEquipe); for($j = 1; $j <= count($tabEquipe); $j++){ if($tabEquipe[$j]['rol_id'] != 3 && $tabEquipe[$j]['rol_id'] != 4) { ?>
fxQuery($sqlUpdate); if (!$qryUpdate) { $blnError = true; fxcreer_log('Erreur lors de la reinitialisation des infos de dossards de l\'epreuve.'); } // resultats_epreuves_commandees $sqlUpdate = "UPDATE resultats_epreuves_commandees SET no_equipe = null WHERE epr_id = " . intval($int_epr_id); $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) { $blnError = true; fxcreer_log('Erreur lors de la reinitialisation des infos de dossards de la commande.'); } // resultats_participants $sqlUpdate = "UPDATE resultats_participants SET no_bib = null, par_date_bib = null WHERE epr_id = " . intval($int_epr_id); $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) { $blnError = true; fxcreer_log('Erreur lors de la reinitialisation des numeros de dossards des participants.'); } if ($blnError) { ?>
Reset Problems - Try again


fxGetResults($sqlInscriptions); $sqlEpreuves = "SELECT * FROM inscriptions_epreuves WHERE epr_id = " . intval($int_epr_id); $tabEpreuves = $objDatabase->fxGetRow($sqlEpreuves); if ($int_par_equipe == 0) { if ($int_finish == 0) $int_finish = $int_start + count($tabInscriptions); for ($i = 1; $i <= count($tabInscriptions); $i++) { if ($tabInscriptions[$i]['rol_id'] != 3 && $tabInscriptions[$i]['rol_id'] != 4) { $sqlUpdate = "UPDATE resultats_participants "; if ($str_action == 'reset') { $sqlUpdate .= "SET no_bib = '', par_date_bib = null"; // $sqlUpdate .= "SET no_bib = ''"; } else { if($tabInscriptions[$i]['par_date_bib'] == null){ $sqlUpdate .= "SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "'"; } else{ $sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "'"; // $sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "', par_maj = '" . fxGetDateTime() . "'"; // $sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "', par_modification_promoteur = 1, par_maj = '" . fxGetDateTime() . "'"; } } $sqlUpdate .= " WHERE par_id = " . $tabInscriptions[$i]['par_id'] . " AND is_cancelled = 0"; $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']); $sqlUpdate = "UPDATE resultats_epreuves_commandees SET no_equipe = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "' WHERE epr_id = " . intval($tabInscriptions[$i]['epr_id']) . " AND pec_id_original = " . $tabInscriptions[$i]['pec_id']; $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) fxcreer_log('Erreur lors de mise a jour du numero de dossard de l\'equipe." ' . $int_epr_id); $intCtr++; } if( $intNoBib + $intCtr>$int_finish_dispo){ break; } } } // assigner no_equipe (+ no_bib) if ($int_par_equipe == 1) { if ($int_finish == 0) { $int_finish = count($tab_data); } $intNumeroEquipe= $int_start; for ($i = 1; $i <= count($tab_data); $i++) { $strNumeroEquipe = $objDatabase->fxEscape($intNumeroEquipe+ $intCtr); $sqlUpdate = "UPDATE resultats_epreuves_commandees SET no_equipe = '" . $strNumeroEquipe. "' WHERE epr_id = " . intval($tab_data[$i]['epr_id']) . " AND pec_id_original = " . $tab_data[$i]['pec_id']; $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) fxcreer_log('Erreur lors de mise a jour du numero de dossard de l\'equipe." ' . $int_epr_id); $intCtrBib = 1; // assigner no_bib aux membres de lequipe // get membres de lequipe $sqlEquipe = "SELECT * FROM resultats_participants p WHERE pec_id = " . $tab_data[$i]['pec_id_original'] . $strOrderBy; $tabEquipe = $objDatabase->fxGetResults($sqlEquipe); for ($j = 1; $j <= count($tabEquipe); $j++) { if ($tabEquipe[$j]['rol_id'] != 3 && $tabEquipe[$j]['rol_id'] != 4) { if($int_mode == 0) { if ($tabEquipe[$j]['rol_id'] == 1) { $intNoBib = $strNumeroEquipe . "0"; } else { $intNoBib = $objDatabase->fxEscape($strNumeroEquipe . $intCtrBib);// "1234"; $intCtrBib++; } } else{ $intNoBib = $strNumeroEquipe; } if($tabInscriptions[$i]['par_date_bib'] == null){ $sqlUpdatePart = "UPDATE resultats_participants SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib). "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); } else{ $sqlUpdatePart = "UPDATE resultats_participants SET no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); // $sqlUpdatePart = "UPDATE resultats_participants SET par_maj = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); // $sqlUpdatePart = "UPDATE resultats_participants SET par_maj = '" . fxGetDateTime() . "', par_modification_promoteur = 1, no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); } $qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart); if (!$qryUpdatePart) fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']); } } $intCtr++; } } // update epreuve $sqlUpdate = "UPDATE inscriptions_epreuves SET epr_bib_finish_dispo=".$int_finish_dispo.", epr_bib_start = " . intval($int_start) . ", epr_bib_finish = " . intval($int_finish) . ", epr_bib_mode = " . intval($int_mode) . ", ba_id = " . intval($int_type) . " WHERE epr_id = " . intval($int_epr_id); $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) fxcreer_log('Erreur lors de mise a jour information dossard" ' . $int_epr_id); // fxShowBibNumbersTable($tab_data, $strLangue); } } function fxShowColumnPromoteur($arrColonnes, $arrListeParticipants, $x, $strLangue, $intEquipe = 0,$abonnement=0) { global $vDomaine ; $strResults = ''; foreach ($arrColonnes as $arrCol) { $arrFields = explode(',', $arrCol['field']); $strAffichage = $arrCol['mask']; switch ($arrCol['format']) { // vérifier le format d'affichage case 'bib': if ($abonnement){ $membre=fxGetAbonnement(0,0,0,$arrListeParticipants[$x]['pec_id_original']); isset($membre['mem_numero'])? $m_membre=$membre['mem_numero'] :$m_membre=""; $strAffichage = '
' . $m_membre . '
'; } else { $intValue = (intval($arrListeParticipants[$x]['pec_equipe']) == 1) ? fxShowBibNumber($arrListeParticipants[$x]['no_equipe'], $arrListeParticipants[$x]['epr_id'], 'equipe') : fxShowBibNumber($arrListeParticipants[$x]['no_bib'], $arrListeParticipants[$x]['epr_id'], 'participant'); $strAffichage = '
'; if (intval($intEquipe) == 1) { $strAffichage .= afficheTexte('promoteur_bib_no_equipe', 0); $strAction = 'no_equipe'; $strId = 'txt_no_bib_e'; } else { $strAffichage .= afficheTexte('promoteur_bib_no_participants', 0); $strAction = 'no_bib'; $strId = 'txt_no_bib_p'; } $strAffichage .= '
'; } break; case 'management': $strCode = fxGetEvenementsUrl($arrListeParticipants[$x]['eve_id']); $strCancelBadge = ''; if ($arrListeParticipants[$x]['is_cancelled'] == '' || $arrListeParticipants[$x]['is_cancelled'] == '0') { $strStyleEdit = $strStyleCancel = ''; $strStyleRetablir = ' d-none'; } else { $strStyleEdit = $strStyleCancel = ' d-none'; $strStyleRetablir = ''; // MSIN-4405 — Cause de l'annulation derivee en lecture seule (transfere / modifie / annule). $strCause = fxGetAnnulationCause($arrListeParticipants[$x]['pec_id_original'], isset($arrListeParticipants[$x]['pec_actif']) ? $arrListeParticipants[$x]['pec_actif'] : null); if ($strCause == 'transfert') { $strBadgeLbl = ($strLangue == 'fr') ? 'Transférée' : 'Transferred'; } elseif ($strCause == 'modif') { $strBadgeLbl = ($strLangue == 'fr') ? 'Modifiée (changement d\'épreuve)' : 'Modified (race change)'; } else { $strBadgeLbl = ($strLangue == 'fr') ? 'Annulée' : 'Cancelled'; } $strCancelBadge = '
' . htmlspecialchars($strBadgeLbl, ENT_QUOTES, 'UTF-8') . '
'; } $strAffichage = $strCancelBadge . ' '; break; case 'details': // bib reception sl affichage check box // print_r($arrListeParticipants[$x]); $intValeur = 0; if ($arrListeParticipants[$x]['no_bib_remis'] == 1) { $strChecked = ' checked'; $intValeur = 0; $strClass = 'btn-success'; $strImage = ''; } else { $strChecked = ""; $intValeur = 1; $strClass = 'btn-primary'; $strImage = ''; } if ($intEquipe == 1 && fxIsParEquipe($arrListeParticipants[$x]['pec_id_original'], $arrListeParticipants[$x]['epr_id'])) { $strAffichage .= ' '; } else { $strAffichage .= afficheTexte('epreuve_individuelle', 0); } break; case 'edit': $strAffichage = fxCheckMAJ($arrListeParticipants[$x]['pec_id_original'], $arrListeParticipants[$x]['par_id'], $strLangue); // a faire sl mettre les deux langues $strAffichage .='

'.afficheTexte('promoteur_bib_enregistre', 0).'
'. $strImage.' '; $strAffichage .='
'; $strAffichage .='
'; $strAffichage .='
'; $strAffichage .=$arrListeParticipants[$x]['no_bib_remis_date']; $strAffichage .='
'; $strAffichage .='
'; $strAffichage .=$arrListeParticipants[$x]['no_bib_remis_par']; break; case 'factures': case 'confirmm': $arrFactures = fxGetFactures($arrListeParticipants[$x]['pec_id_original']); // trouver toutes les factures pour cette épreuve if ($arrFactures != null) { $strAffichageTemp = ''; for ($intCtr2 = 1; $intCtr2 <= count($arrFactures); $intCtr2++) { $strAffichageTemp .= $strAffichage; if ($intCtr2 > 1) { $strAffichageTemp .= '
'; } foreach ($arrFields as $intIndex => $strField) { // remplacer {x} dans le mask de la colonne $strAffichageTemp = str_replace('{' . $intIndex . '}', $arrListeParticipants[$x][fxchecklanguePromoteur($strField, $arrCol['multilingue'], $strLangue)], $strAffichageTemp); } } $strAffichage = $strAffichageTemp; } break; case 'race': foreach ($arrFields as $intIndex => $strField) { // remplacer {x} dans le mask de la colonne $strReplace = fxGetTabInscription(fxchecklanguePromoteur($strField, $arrCol['multilingue'], $strLangue), $arrListeParticipants[$x]['epr_id'], 'epreuves', 'epr'); if (trim($strReplace) != '') { $strReplace .= '
'; } $strAffichage = str_replace('{' . $intIndex . '}', $strReplace, $strAffichage); } break; case 'money': //format dollar foreach ($arrFields as $intIndex => $strField) { // remplacer {x} dans le mask de la colonne $strAffichage = str_replace('{' . $intIndex . '}', fxShowPrix($arrListeParticipants[$x][fxchecklanguePromoteur($strField, $arrCol['multilingue'], $strLangue)], $strLangue), $strAffichage); } break; default: if ($arrCol['format'] == 'participant') { if (fxIsParEquipe($arrListeParticipants[$x]['pec_id_original'], $arrListeParticipants[$x]['epr_id'])) { $tabCapitaine = fxGetCapitaine($arrListeParticipants[$x]['pec_id'], $arrListeParticipants[$x]['epr_id']); if ($tabCapitaine != null) { $arrListeParticipants[$x]['par_prenom'] = $tabCapitaine['par_prenom']; $arrListeParticipants[$x]['par_nom'] = $tabCapitaine['par_nom']; } /* else afficheTexte('promoteur_no_captain'); */ } } foreach ($arrFields as $intIndex => $strField) { // remplacer {x} dans le mask de la colonne // $strField ici {}on change par la valeur du champ le champ $strAffichage = str_replace('{' . $intIndex . '}', $arrListeParticipants[$x][fxchecklanguePromoteur($strField, $arrCol['multilingue'], $strLangue)], $strAffichage); } // MSIN-3679 patch eve_id $eve_idcode=urlencode(base64_encode($arrListeParticipants[$x]['eve_id'])) ; $strAffichage = str_replace('{99}',$eve_idcode, $strAffichage); } if ($arrCol['format'] == 'team') { //si épreuve solo, ne pas afficher lev nom d'équipe if ($intEquipe != 1) { $strAffichage = ''; } } /* if (count($arrFields) == 1 && trim($arrListeParticipants[$x][fxchecklanguePromoteur($arrFields[0], $arrCol['multilingue'], $strLangue)]) == '') { // si la valeur est vide, ne rien afficher $strAffichage = ''; } */ $strResults .= '' . $strAffichage . ''; } return $strResults; } function fxchecklanguePromoteur($strField, $intMultilingue, $langues) { if (intval($intMultilingue) == 1) return $strField . "_" . $langues; else return $strField; } function fxGetchampsPromoteur($blnDon, $strLangue) { global $vDomaine, $vRepertoireFichiers; if ($blnDon) { $arrColonnes = array( 1 => array( 'field' => 'com_nom,com_prenom', 'align' => 'left', 'format' => 'string', 'mask' => '{0}, {1}', 'multilingue' => 0, 'label_fr' => 'Donateur', 'label_en' => 'Donator' ), 2 => array( 'field' => 'epr_categorie,epr_type,epr_nom', 'align' => 'left', 'format' => 'race', 'mask' => '{0}{1}{2}', 'multilingue' => 1, 'label_fr' => 'Épreuve', 'label_en' => 'Race' ), 3 => array( 'field' => 'pec_nom_equipe', 'align' => 'left', 'format' => 'team', 'mask' => '{0}', 'multilingue' => 0, 'label_fr' => ' Équipe', 'label_en' => 'Team' ), 4 => array( 'field' => 'par_nom,par_prenom', 'align' => 'left', 'format' => 'string', 'mask' => '{0}, {1}', 'multilingue' => 0, 'label_fr' => 'Participant', 'label_en' => 'Participant' ), 5 => array( 'field' => 'pd_montant', 'align' => 'right', 'format' => 'money', 'mask' => '{0}', 'multilingue' => 0, 'label_fr' => 'Montant', 'label_en' => 'Amount' ), 6 => array( 'field' => 'no_panier,no_commande', 'align' => 'left', 'format' => ' factures', 'mask' => '{1}', 'multilingue' => 0, 'label_fr' => '# commande', 'label_en' => 'Order #' ), 7 => array( 'field' => 'pd_recu_pdf', 'align' => 'left', 'format' => 'string', 'mask' => 'PDF', 'multilingue' => 0, 'label_fr' => 'Reçu', 'label_en' => 'Receipt' ) ); } else { $strRenvoi = ($strLangue == 'fr') ? "RENVOI" : "RESEND"; $arrColonnes = array( 1 => array( 'field' => 'epr_categorie,epr_type,epr_nom', 'align' => 'left', 'format' => 'race', 'mask' => '{0}{1}{2}', 'multilingue' => 1, 'label_fr' => 'Épreuve', 'label_en' => 'Race' ), 2 => array( 'field' => 'par_nom,par_prenom', 'align' => 'left', 'format' => '^particpant', 'mask' => '{0}, {1}', 'multilingue' => 0, 'label_fr' => 'Nom du participant', 'label_en' => 'Participant\'s name' ), 3 => array( 'field' => '', 'align' => 'left', 'format' => 'bib', 'mask' => '', 'multilingue' => 0, 'label_fr' => afficheTexte('promoteur_bib_number', 0), 'label_en' => afficheTexte('promoteur_bib_number', 0) ), 4 => array( 'field' => '', 'align' => 'left', 'format' => 'details', 'mask' => '', 'multilingue' => 0, 'label_fr' => 'Détails', 'label_en' => 'Details' ),5 => array( 'field' => '', 'align' => 'left', 'format' => 'management', 'mask' => '', 'multilingue' => 0, 'label_fr' => 'Gestion', 'label_en' => 'Management' ), 6 => array( 'field' => '', 'align' => 'left', 'format' => 'edit', 'mask' => '', 'multilingue' => 0, 'label_fr' => 'Modifiée', 'label_en' => 'Modified' ), 7 => array( 'field' => 'no_panier,no_commande', 'align' => 'left', 'format' => 'string',// MSIN-3679 'mask' => '{1}
', 'multilingue' => 0, 'label_fr' => '# commande', 'label_en' => 'Order #' ), 8 => array( 'field' => 'no_panier,no_commande', 'align' => 'left', 'format' => 'confirm', 'mask' => '', 'multilingue' => 0, 'label_fr' => 'Confirmation', 'label_en' => 'Confirmation' ) ); } return $arrColonnes; } function fxSetBibManuel($strAction, $intEvenement, $intNewNoBib, $intEpreuveCommandee, $intEpreuve, $intPartipcipant, $strLangue = 'fr') { global $objDatabase; $arrRetour = array('state' => 'error'); $intEveId = base64_decode(urldecode($intEvenement)); $_SESSION['promoteur_eve_id'] = base64_decode(urldecode($intEvenement)); $sqlEpreuve = "SELECT * FROM inscriptions_epreuves WHERE epr_id = " . intval($intEpreuve); $tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve); $strBib = $intNewNoBib; $sqlTeam = "SELECT * FROM resultats_participants WHERE pec_id = " . intval($intEpreuveCommandee) . " ORDER BY no_bib"; $tabTeam = $objDatabase->fxGetResults($sqlTeam); switch($strAction) { case 'no_bib': if ($tabEpreuve['epr_equipe'] == 0 || ($tabEpreuve['epr_equipe'] == 1 && $tabEpreuve['epr_bib_mode'] == 1)) { // verifier si new_no_bib existe $sqlNoBib = "SELECT no_bib FROM resultats_participants WHERE no_bib LIKE '%" . "-" . $intNewNoBib . "' AND eve_id = " . intval($intEveId); $qryNoBib = $objDatabase->fxGetResults($sqlNoBib); if ($qryNoBib != null) { if ($strLangue == 'fr') $_SESSION['msg'] = 'p155'; else $_SESSION['msg'] = 'p555'; } $sqlUpdate = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = '" . fxUnescape($strBib) . "', par_maj = '" . fxGetDateTime() . "' WHERE epr_id = " . intval($intEpreuve) . " AND par_id = " . intval($intPartipcipant); $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if (!$qryUpdate) { fxcreer_log("Erreur durant assignation manuelle du numero de dossard (" . $intPartipcipant . ")"); } else { if (function_exists('fxEvtErreurResoudre')) { fxEvtErreurResoudre('bib_auto_miss', (int)$intEpreuve, (int)$intPartipcipant); } $arrRetour['state'] = 'success'; } } elseif($tabEpreuve['epr_equipe'] == 1 && $tabEpreuve['epr_bib_mode'] == 0) { $sqlUpdateTeamPart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = '" . $intNewNoBib . "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . intval($intPartipcipant); $qryUpdateTeam = $objDatabase->fxQuery($sqlUpdateTeamPart); if (!$qryUpdateTeam) { fxcreer_log("Erreur durant assignation manuelle du numero de dossard (" . $intPartipcipant . ")"); } else { if (function_exists('fxEvtErreurResoudre')) { fxEvtErreurResoudre('bib_auto_miss', (int)$intEpreuve, (int)$intPartipcipant); } $arrRetour['state'] = 'success'; } } break; case 'no_equipe': if ($tabEpreuve['epr_equipe'] == 1 && $strAction == 'no_equipe') { // verifier si new_no_bib existe $sqlNoBib = "SELECT no_equipe FROM resultats_epreuves_commandees WHERE no_equipe LIKE '%" . $intNewNoBib . "' AND eve_id = " . intval($intEveId); $qryNoBib = $objDatabase->fxGetResults($sqlNoBib); if ($qryNoBib != null) { if ($strLangue == 'fr') $_SESSION['msg'] = 'p156'; else $_SESSION['msg'] = 'p556'; } if ($strAction == 'no_equipe') { // update no_equipe $sqlUpdate = "UPDATE resultats_epreuves_commandees SET no_equipe = '" . fxUnescape($strBib) . "' WHERE pec_id_original = " . intval($intEpreuveCommandee); $qryUpdate = $objDatabase->fxQuery($sqlUpdate); } $intCtr = 1; for ($i = 1; $i <= count($tabTeam); $i++) { if ($strAction == 'no_equipe' && $tabEpreuve['epr_bib_mode'] == 0) { if (intval($tabTeam[$i]['rol_id']) == 1) { $sqlUpdatePart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = " . intval($strBib) * 10 . ", par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . intval($tabTeam[$i]['par_id']); } else { $sqlUpdatePart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = '" . $strBib . $intCtr . "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . intval($tabTeam[$i]['par_id']); $intCtr++; } $qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart); if (!$qryUpdate) { fxcreer_log("Erreur durant assignation manuelle du numero d'équipe (" . $intEpreuveCommandee . ")"); } } else { $sqlUpdatePart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = '" . $strBib . "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . intval($tabTeam[$i]['par_id']); $qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart); if (!$qryUpdatePart) { fxcreer_log("Erreur durant assignation manuelle du numero de dossard (" . $intPartipcipant . ")"); } } } if (!$qryUpdate) { fxcreer_log("Erreur durant assignation manuelle du numero d'équipe (" . $intEpreuveCommandee . ")"); } else { $arrRetour['state'] = 'success'; } } break; } return $arrRetour; } function fxSetParStatutCourse($intPartipcipant, $strStatutCode, $strLangue = 'fr') { global $objDatabase; $arrRetour = array('state' => 'error'); $intParId = intval($intPartipcipant); $strCode = trim((string)$strStatutCode); if ($intParId <= 0 || $strCode === '') { return $arrRetour; } $sqlCheck = "SELECT 1 FROM info WHERE info_actif = 1 AND info_clef = 'inscr_statut_course'" . " AND info_description = 'opt' AND info_option2 = '" . $objDatabase->fxEscape($strCode) . "' LIMIT 1"; if ($objDatabase->fxGetRow($sqlCheck) === null) { return $arrRetour; } $sqlUpdate = "UPDATE resultats_participants SET par_modification_promoteur = 1," . " par_statut_course = '" . $objDatabase->fxEscape($strCode) . "'," . " par_maj = '" . fxGetDateTime() . "'" . " WHERE par_id = " . $intParId; if ($objDatabase->fxQuery($sqlUpdate)) { $arrRetour['state'] = 'success'; } else { fxcreer_log('Erreur durant mise a jour statut course (' . $intParId . ')'); } return $arrRetour; } function fxShowTeammates($intEvenement, $intEpreuve, $intEpreuveCommandee) { $arrRetour = array('state' => 'error'); $tabEquipe = fxGetMembresEquipe($intEvenement, $intEpreuveCommandee, $intEpreuve, 0, 1); if ($tabEquipe != null) { $arrRetour['state'] = 'success'; $arrRetour['team'] = fxUnescape($tabEquipe[1]['pec_nom_equipe']); $strMembers = ''; for ($i = 1; $i <= count($tabEquipe); $i++) { $strMembers .= '
'; } $arrRetour['members'] = $strMembers; } return $arrRetour; } function fxGetQuantitesEvenement($intEpreuve) { global $objDatabase; $arrRetour = array(); $intTotalOriginal = $intTotalAvailable = $intTotalBooked = $intTotalCurrent = $intTotalAjustement = 0; // récupérer toutes les épreuves de l'événement de $intEpreuve $sqlEpreuves = "SELECT epr_id FROM inscriptions_epreuves WHERE eve_id = (SELECT DISTINCT eve_id FROM inscriptions_epreuves WHERE epr_id = " . intval($intEpreuve) . ") AND epr_actif = 1"; $arrEpreuves = $objDatabase->fxGetResults($sqlEpreuves); if ($arrEpreuves != null) { for ($intCtr = 1; $intCtr <= count($arrEpreuves); $intCtr++) { $tabEpreuve = fxGetEpreuve($arrEpreuves[$intCtr]['epr_id']); $sqlInscriptions = 'select p.no_bib, p.par_id, p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, p.rol_id, e.no_commande, e.no_panier, e.no_equipe from resultats_epreuves_commandees e, resultats_participants p where p.is_cancelled = 0 AND p.epr_id = ' . intval($tabEpreuve['epr_id']) . ' AND p.epr_id = e.epr_id and p.pec_id = e.pec_id_original group by e.pec_id_original'; $tabInscriptions = $objDatabase->fxGetResults($sqlInscriptions); $intNbInscriptions = count($tabInscriptions); $intTotalOriginal += $tabEpreuve['epr_qte_origine']; $intTotalAvailable += $tabEpreuve['epr_qte']; $intTotalBooked += $intNbInscriptions; $intTotalCurrent += intval($intNbInscriptions) + intval($tabEpreuve['epr_qte']); $intTotalAjustement += intval($intNbInscriptions) + intval($tabEpreuve['epr_qte']) - intval($tabEpreuve['epr_qte_origine']); $checkin=fxGetCheckinqte($arrEpreuves[$intCtr]['epr_id']); $arrRetour[$arrEpreuves[$intCtr]['epr_id']] = array( 'qte_origine' => intval($tabEpreuve['epr_qte_origine']), 'qte_restante' => intval($tabEpreuve['epr_qte']), 'qte_inscrits' => intval($intNbInscriptions), 'qte_courante' => intval($intNbInscriptions) + intval($tabEpreuve['epr_qte']), 'qte_ajustement' => intval($intNbInscriptions) + intval($tabEpreuve['epr_qte']) - intval($tabEpreuve['epr_qte_origine']), 'qte_checkin' => intval($checkin) ); } $arrRetour['total'] = array( 'qte_origine_total' => $intTotalOriginal, 'qte_restante_total' => $intTotalAvailable, 'qte_inscrits_total' => $intTotalBooked, 'qte_courante_total' => $intTotalCurrent, 'qte_ajustement_total' => $intTotalAjustement ); } return $arrRetour; } function fxGetQuantites($intEpreuve) { global $objDatabase; $tabEpreuve = fxGetEpreuve($intEpreuve); $sqlCommandees = "SELECT COUNT(*) FROM inscriptions_panier_epreuves_commandees e, inscriptions_panier_acheteurs a WHERE e.epr_id = " . intval($tabEpreuve['epr_id']) . " AND e.no_panier = a.no_panier AND a.sta_id = 3"; $intQteCommandees = $objDatabase->fxGetVar($sqlCommandees); $sqlInscriptions = 'select p.no_bib, p.par_id, p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, p.rol_id, e.no_commande, e.no_panier, e.no_equipe from resultats_epreuves_commandees e, resultats_participants p where p.is_cancelled = 0 AND p.epr_id = ' . intval($intEpreuve) . ' AND p.epr_id = e.epr_id and p.pec_id = e.pec_id_original group by e.pec_id_original'; $tabInscriptions = $objDatabase->fxGetResults($sqlInscriptions); $intNbInscriptions = count($tabInscriptions); $arrRetour = array( 'qte_origine' => intval($tabEpreuve['epr_qte_origine']), 'qte_restante' => intval($tabEpreuve['epr_qte']), 'qte_inscrits' => intval($intNbInscriptions), 'qte_courante' => intval($intNbInscriptions) + intval($tabEpreuve['epr_qte']), 'qte_ajustement' => intval($intNbInscriptions) + intval($tabEpreuve['epr_qte']) - intval($tabEpreuve['epr_qte_origine']) ); return $arrRetour; } function fxUpdateQuantites($intEpreuve, $intQuantite, $strLangue) { global $objDatabase; $arrRetour = array('state' => 'error'); if ($intQuantite >= 0) { $tabEpreuve = fxGetEpreuve($intEpreuve); $intDifference = $intQuantite - $tabEpreuve['epr_qte']; $sqlUpdate = "UPDATE inscriptions_epreuves SET epr_qte_ajoutee = epr_qte_ajoutee + " . intval($intDifference) . ", epr_qte = epr_qte + " . intval($intDifference) . " WHERE epr_id = " . intval($intEpreuve); $qryUpdate = $objDatabase->fxQuery($sqlUpdate); if ($qryUpdate) { if($strLangue == 'fr') $_SESSION['msg'] = 'p154'; else $_SESSION['msg'] = 'p554'; } $arrRetour['data'] = fxGetQuantitesEvenement($intEpreuve); $arrRetour['state'] = 'success'; } return $arrRetour; } // v2 — encart « choisissez vos séquences » (batch + auto) function renderBibBatchPickPrompt() { ob_start(); ?>

Commencer à partir de la dernière assignation */ ?>

'inc_tableau_gestion_epreuves', 'epreuves' => 'inc_tableau_epreuves', 'dossards' => 'inc_tableau_dossards', 'promoteur' => 'inc_tableau_promoteur', ); $strFrom = (isset($_GET['from']) && trim($_GET['from']) !== '') ? trim($_GET['from']) : $strDefault; if (!isset($arrAllowed[$strFrom])) { $strFrom = $strDefault; } $strEveParam = 'promoteur_eve_id=' . urlencode(base64_encode($intEveId)); return $vDomaine . $strPage . '/' . $arrAllowed[$strFrom] . '?' . $strEveParam; } /** Chemin relatif (sans domaine) pour strhomeclientannuler et liens internes. */ function fxGetPromoteurBackPath($strPage = '/compte', $strDefault = 'promoteur') { $arrAllowed = array( 'gestion' => 'inc_tableau_gestion_epreuves', 'epreuves' => 'inc_tableau_epreuves', 'dossards' => 'inc_tableau_dossards', 'promoteur' => 'inc_tableau_promoteur', ); $strFrom = (isset($_GET['from']) && trim($_GET['from']) !== '') ? trim($_GET['from']) : $strDefault; if (!isset($arrAllowed[$strFrom])) { $strFrom = $strDefault; } return $strPage . '/' . $arrAllowed[$strFrom]; } /** Jeton CSRF du module dossards v4 (session). */ function fxBibCsrfToken($mem_regenerate = false) { if (empty($_SESSION['bib_csrf_token']) || $mem_regenerate) { $_SESSION['bib_csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['bib_csrf_token']; } /** Valide le jeton CSRF reçu en POST (ajax_bib_range save_auto_config, etc.). */ function fxBibValidateCsrf($str_token) { if ($str_token === '' || empty($_SESSION['bib_csrf_token'])) { return false; } return hash_equals($_SESSION['bib_csrf_token'], $str_token); } /** Session promoteur ou admin requise pour les actions AJAX sensibles du module bib. */ function fxBibRequirePromoteurSession() { return !empty($_SESSION['com_id']) || !empty($_SESSION['usa_id']); } /** Resout eve_id depuis la requete AJAX bib (eve_id direct ou via epr_id). */ function fxBibResolveEveIdFromRequest() { global $objDatabase; if (!empty($_REQUEST['eve_id'])) { return intval($_REQUEST['eve_id']); } $intEprId = intval($_REQUEST['epr_id'] ?? 0); if ($intEprId <= 0) { return 0; } $intEveId = intval($objDatabase->fxGetVar( 'SELECT eve_id FROM inscriptions_epreuves WHERE epr_id = ' . $intEprId . ' LIMIT 1' )); return ($intEveId > 0) ? $intEveId : 0; } /** Gate AJAX bib v4 — session, droits v2 par evenement (usa_id = bypass), CSRF. */ function fxBibRequireAjaxAccess() { if (!fxBibRequirePromoteurSession()) { echo json_encode([ 'success' => false, 'message' => fxBibMsg('bib_v4_ajax_session_invalid'), ]); exit; } if (empty($_SESSION['usa_id'])) { require_once __DIR__ . '/inc_fx_eve_acces.php'; $intComId = intval($_SESSION['com_id'] ?? 0); $intEveId = fxBibResolveEveIdFromRequest(); if ($intComId <= 0 || $intEveId <= 0 || !fxEveAccesHasAnyPermission($intComId, $intEveId, array('dossards.manage', 'epreuves.edit_qte'))) { echo json_encode([ 'success' => false, 'message' => fxBibMsg('bib_v4_ajax_unauthorized'), ]); exit; } } $strToken = $_POST['csrf_token'] ?? $_REQUEST['csrf_token'] ?? ''; if (!fxBibValidateCsrf($strToken)) { echo json_encode([ 'success' => false, 'message' => fxBibMsg('bib_v4_ajax_unauthorized'), ]); exit; } } /** Échappement HTML pour attributs Tippy / boutons bib v4. */ function fxBibEsc($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); } /** Page info pour le module bib v4 — toujours compte.php, jamais le script AJAX. */ function fxBibInfoPage() { return 'compte.php'; } /** * Lit info_texte / info_aide depuis $vtexte_page ou la BD (compte.php / global uniquement). * N'écrit jamais dans info — évite les doublons info_prg=ajax_bib_range.php en AJAX. */ function fxBibGetInfoRow($clef) { global $vtexte_page, $objDatabase, $strLangue; if (!empty($vtexte_page[$clef])) { return $vtexte_page[$clef]; } static $bibInfoCache = array(); if (array_key_exists($clef, $bibInfoCache)) { return $bibInfoCache[$clef]; } if (!isset($objDatabase)) { $bibInfoCache[$clef] = array(); return $bibInfoCache[$clef]; } $strLang = !empty($strLangue) ? $strLangue : 'fr'; $strPage = fxBibInfoPage(); $sql = "SELECT info_texte, info_aide FROM info WHERE info_actif = 1 AND info_clef = '" . $objDatabase->fxEscape($clef) . "' AND info_langue = '" . $objDatabase->fxEscape($strLang) . "' AND info_prg IN ('" . $strPage . "', 'global') ORDER BY FIELD(info_prg, '" . $strPage . "', 'global') LIMIT 1"; $row = $objDatabase->fxGetRow($sql); if (!is_array($row) || empty($row)) { // Entrées legacy créées par erreur sous ajax_bib_range.php — lecture seule. $sqlLegacy = "SELECT info_texte, info_aide FROM info WHERE info_actif = 1 AND info_clef = '" . $objDatabase->fxEscape($clef) . "' AND info_langue = '" . $objDatabase->fxEscape($strLang) . "' AND info_prg = 'ajax_bib_range.php' LIMIT 1"; $row = $objDatabase->fxGetRow($sqlLegacy); } $bibInfoCache[$clef] = is_array($row) ? $row : array(); return $bibInfoCache[$clef]; } /** Libellé bib v4 — sur compte.php auto-crée si absent ; en AJAX, lecture seule. * $blnAllowEmptyLabel : si true, info_texte vide en BD reste vide (en-têtes colonnes éditables). */ function fxBibTexte($clef, $mem_echo = 0, $blnAllowEmptyLabel = false) { $row = fxBibGetInfoRow($clef); $blnHasDbRow = !empty($row) && array_key_exists('info_texte', $row); $str = trim($row['info_texte'] ?? ''); if ($blnAllowEmptyLabel && $blnHasDbRow && $str === '') { if ($mem_echo) { echo ''; } return ''; } if ($str === '' || $str === $clef || $str === '*' . $clef . '*') { if (!defined('MS1_BIB_AJAX') || !MS1_BIB_AJAX) { if (!$blnHasDbRow && !$blnAllowEmptyLabel) { $str = trim(afficheTexte($clef, 0)); } } if ($str === '' || $str === $clef || $str === '*' . $clef . '*') { $str = fxBibStaticFallback($clef); if ($str === '') { $str = $blnAllowEmptyLabel ? '' : $clef; } } } if ($mem_echo) { echo fxBibEsc($str); } return $str; } /** Repli FR/EN si clé bib_v4 absente ou mal saisie en BD. */ function fxBibStaticFallback($clef) { global $strLangue; $lng = ($strLangue === 'en') ? 'en' : 'fr'; $tab = [ 'bib_v4_view_cancelled' => ['fr' => 'Annulé', 'en' => 'Cancelled'], 'bib_v4_err_gaps' => ['fr' => 'Dossards non assignés :', 'en' => 'Unassigned bibs:'], 'bib_v4_err_dupes' => ['fr' => 'Dossards en double :', 'en' => 'Duplicate bibs:'], 'bib_v4_anomalies_auto_miss_title' => ['fr' => 'Inscriptions sans dossard (auto)', 'en' => 'Registrations without a bib (auto)'], 'bib_v4_anomalies_out_of_range_title' => ['fr' => 'Dossards hors séquence', 'en' => 'Bibs outside sequences'], 'bib_v4_anomalies_no_range' => ['fr' => 'Aucune séquence configurée', 'en' => 'No sequence configured'], 'bib_v4_anomalies_order_fmt' => ['fr' => 'Commande %s', 'en' => 'Order %s'], 'bib_v4_anomalies_assign_link' => ['fr' => 'Assigner un dossard', 'en' => 'Assign a bib'], 'bib_v4_js_loader_wait' => ['fr' => 'Chargement...', 'en' => 'Loading...'], 'bib_v4_js_global_no_epr' => ['fr' => 'Sélectionnez au moins une épreuve solo.', 'en' => 'Select at least one solo race.'], 'bib_v4_js_global_no_seq' => ['fr' => 'Cochez au moins une séquence pour les épreuves sélectionnées.', 'en' => 'Check at least one sequence for the selected races.'], 'bib_v4_global_batch_plan_invalid' => ['fr' => 'Sélection invalide : choisissez au moins une épreuve solo et des séquences.', 'en' => 'Invalid selection: pick at least one solo race and sequences.'], 'bib_v4_global_batch_need_two' => ['fr' => "L'assignation globale nécessite au moins deux épreuves solo avec des séquences disponibles.", 'en' => 'Global assignment requires at least two solo races with available sequences.'], 'bib_v4_ajax_global_sim_summary' => ['fr' => '%d épreuve(s) · %d dispo / %d à assigner → %d assignables (%d manque)', 'en' => '%d race(s) · %d avail. / %d to assign → %d assignable (%d short)'], ]; return $tab[$clef][$lng] ?? ''; } /** Libellé « Annulé » dans la vue dossards — repli si clé BD absente ou mal saisie. */ function fxBibViewCancelledLabel($strLangue = 'fr') { $str = fxBibTexte('bib_v4_view_cancelled', 0); if ($str === '' || $str === 'bib_v4_view_cancelled' || $str === '*bib_v4_view_cancelled*') { return ($strLangue === 'en') ? 'Cancelled' : 'Annulé'; } return $str; } /** Message bib v4 avec placeholders sprintf (%d, %s…) — AJAX et vues dynamiques. */ function fxBibMsg($clef, ...$args) { $str = fxBibTexte($clef, 0); if (!empty($args)) { return vsprintf($str, $args); } return $str; } /** Crayon traduction bib v4 (page info bib). */ function fxBibTradButton($clef) { return fxAdminTradButton($clef, fxBibInfoPage()); } /** Texte bib + crayon si mode Textes actif. */ function fxBibTexteTrad($clef, $mem_echo = 0, $blnAllowEmptyLabel = false) { $html = fxBibEsc(fxBibTexte($clef, 0, $blnAllowEmptyLabel)) . fxBibTradButton($clef); if ($mem_echo) { echo $html; } return $html; } /** Message sprintf + crayon. */ function fxBibMsgTrad($clef, ...$args) { return fxBibEsc(fxBibMsg($clef, ...$args)) . fxBibTradButton($clef); } /** Clé site promoteur_* puis repli bib_v4_* + crayon sur la clé bib. */ function fxBibSiteOrBibTexteTrad($strSiteClef, $strBibClef, $mem_echo = 0) { $html = fxBibEsc(fxBibSiteOrBibTexte($strSiteClef, $strBibClef)) . fxBibTradButton($strBibClef); if ($mem_echo) { echo $html; } return $html; } /** Description d'une épreuve en conflit : type + catégorie (langue courante), (inactive) si epr_actif = 0. */ function fxBibEpreuveDisplayName(array $row, $strLangue = 'fr') { $strLangue = in_array($strLangue, ['fr', 'en'], true) ? $strLangue : 'fr'; $strAlt = $strLangue === 'fr' ? 'en' : 'fr'; $strType = trim($row['epr_type_' . $strLangue] ?? ''); if ($strType === '') { $strType = trim($row['epr_type_' . $strAlt] ?? ''); } $strCat = trim($row['epr_categorie_' . $strLangue] ?? ''); if ($strCat === '') { $strCat = trim($row['epr_categorie_' . $strAlt] ?? ''); } $parts = []; if ($strType !== '') { $parts[] = $strType; } if ($strCat !== '') { $parts[] = $strCat; } $str = implode(' ', $parts); if ($str === '') { $strNom = trim($row['epr_nom_' . $strLangue] ?? ''); if ($strNom === '') { $strNom = trim($row['epr_nom_' . $strAlt] ?? ''); } $str = $strNom; } if ($str === '' && !empty($row['epr_id'])) { $str = '#' . (int)$row['epr_id']; } if ((int)($row['epr_actif'] ?? 1) === 0) { $strInactive = trim(fxBibTexte('bib_v4_ajax_overlap_inactive', 0)); if ($strInactive !== '' && $strInactive !== 'bib_v4_ajax_overlap_inactive') { $str .= ' (' . $strInactive . ')'; } } return $str; } /** * Séquences de dossards qui chevauchent [start, end] sur le même événement. * @return array|null Tableau 1-based fxGetResults, ou null si paramètres invalides. */ function fxBibGetOverlappingRanges($eve_id, $start, $end, $exclude_bib_id = 0) { global $objDatabase; $eve_id = (int)$eve_id; $start = (int)$start; $end = (int)$end; $exclude_bib_id = (int)$exclude_bib_id; if ($eve_id <= 0 || $start <= 0 || $end <= 0) { return null; } $sqlExclude = ($exclude_bib_id > 0) ? "AND b.epr_bib_id <> $exclude_bib_id" : ''; $sql = " SELECT b.epr_bib_id, b.epr_id, b.epr_bib_start, b.epr_bib_finish, e.epr_nom_fr, e.epr_nom_en, e.epr_type_fr, e.epr_type_en, e.epr_categorie_fr, e.epr_categorie_en, e.epr_actif FROM inscriptions_epreuves_bib b INNER JOIN inscriptions_epreuves e ON e.epr_id = b.epr_id WHERE b.eve_id = $eve_id AND b.epr_bib_start IS NOT NULL AND b.epr_bib_finish IS NOT NULL $sqlExclude AND ($start <= b.epr_bib_finish AND $end >= b.epr_bib_start) ORDER BY b.epr_bib_start, b.epr_bib_id "; return $objDatabase->fxGetResults($sql); } /** Message d'erreur détaillé pour un chevauchement de séquences de dossards. */ function fxBibFormatOverlapConflictMessage($tabOverlaps, $strLangue = 'fr') { if (empty($tabOverlaps) || !is_array($tabOverlaps)) { return fxBibTexte('bib_v4_ajax_overlap', 0); } $entries = []; $firstRow = null; foreach ($tabOverlaps as $row) { if (!is_array($row)) { continue; } if ($firstRow === null) { $firstRow = $row; } $entries[] = fxBibMsg( 'bib_v4_ajax_overlap_entry', fxBibEpreuveDisplayName($row, $strLangue), (int)$row['epr_bib_start'], (int)$row['epr_bib_finish'] ); } if (empty($entries) || $firstRow === null) { return fxBibTexte('bib_v4_ajax_overlap', 0); } if (count($entries) === 1) { return fxBibMsg( 'bib_v4_ajax_overlap', (int)$firstRow['epr_bib_start'], (int)$firstRow['epr_bib_finish'], fxBibEpreuveDisplayName($firstRow, $strLangue) ); } return fxBibMsg('bib_v4_ajax_overlap_many', implode('; ', $entries)); } /** MSIN-4379 — Attributs data-js-* injectés dans #module-bib pour le JS client. */ function fxBibModuleJsDataAttrs() { $map = [ 'loader-wait' => 'bib_v4_js_loader_wait', 'server-error' => 'bib_v4_js_server_error', 'fields-required' => 'bib_v4_js_fields_required', 'auto-select-count' => 'bib_v4_js_auto_select_count', 'batch-none' => 'bib_v4_js_batch_none_selected', 'batch-summary-ok' => 'bib_v4_js_batch_summary_ok', 'reset-warning' => 'bib_v4_js_reset_warning', 'auto-disable-confirm'=> 'bib_v4_js_auto_disable_confirm', 'no-seq-selected' => 'bib_v4_ajax_no_seq_selected', 'err-generic' => 'bib_v4_ajax_error', 'batch-summary-short' => 'bib_v4_ajax_sim_summary', 'batch-reset-count' => 'bib_v4_ajax_reset_preview_count', 'auto-select-hint' => 'bib_v4_auto_select_hint', 'lock-confirm' => 'bib_v4_js_lock_confirm', 'unlock-confirm' => 'bib_v4_js_unlock_confirm', 'auto-pending-bibs' => 'bib_v4_js_auto_pending_bibs', 'range-incomplete' => 'bib_v4_js_range_incomplete', 'range-invalid' => 'bib_v4_js_range_invalid', 'range-invalid-end' => 'bib_v4_js_range_invalid_end', 'range-invalid-qty' => 'bib_v4_js_range_invalid_qty', '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', 'assign-full' => 'bib_v4_ajax_assign_full', 'assign-partial' => 'bib_v4_ajax_assign_partial', 'assign-none' => 'bib_v4_ajax_assign_none', ]; $html = ''; foreach ($map as $attr => $clef) { $html .= ' data-js-' . $attr . '="' . fxBibEsc(fxBibTexte($clef, 0)) . '"'; } return $html; } /** Texte d'aide long bib v4 — même règle que fxBibTexte pour l'auto-création. */ function fxBibAide($clef, $mem_echo = 0) { $row = fxBibGetInfoRow($clef); $str = trim($row['info_aide'] ?? ''); if ($str === '' && (!defined('MS1_BIB_AJAX') || !MS1_BIB_AJAX)) { $str = trim(afficheAide($clef, 0)); } if ($mem_echo) { echo fxBibEsc($str); } return $str; } /** Attribut data-tippy-content — info_aide (tips sur icônes œil, colonnes sans libellé, etc.). */ function fxBibAideTippyAttr($clef) { $strTip = trim(fxBibAide($clef, 0)); if ($strTip === '') { return ''; } return ' data-tippy-content="' . fxBibEsc($strTip) . '"'; } /** Attribut data-tippy-content — texte court depuis info_texte (clé bib_v4_tip_*). */ function fxBibTippyAttr($clef) { $strTip = trim(fxBibTexte($clef, 0)); if ($strTip === '' || $strTip === '*' . $clef . '*') { return ''; } return ' data-tippy-content="' . fxBibEsc($strTip) . '"'; } /** Classe CSS de visibilité — toujours appliquée au conteneur entier (bouton + ?). */ function fxBibUiHiddenClass($blnVisible) { return $blnVisible ? '' : ' bib-ui-hidden'; } /** Contenu aide (?) — texte caché ; espace visuel avant le rond via CSS (.epr-action-group gap). */ function fxBibAideInner($clef) { $strAide = trim(fxBibAide($clef, 0)); if ($strAide === '') { return ''; } return '?'; } /** Bouton (?) rond + crayon traduction (via fxAdminTradButton) — $strTone optionnel. */ function fxBibAideButton($clef, $strTone = '', $blnWithTrad = true) { $strHtml = ''; $strInner = fxBibAideInner($clef); if ($strInner !== '') { $strClass = 'btn-aide-bib bib-aide-trigger'; if ($strTone !== '') { $strClass .= ' btn-aide-tone-' . preg_replace('/[^a-z0-9-]/', '', $strTone); } $strHtml = ''; } if ($blnWithTrad) { $strHtml .= fxAdminTradButton($clef, fxBibInfoPage()); } return $strHtml; } /** Clé site promoteur_* puis repli bib_v4_* si absent en BD. */ function fxBibSiteOrBibTexte($strSiteClef, $strBibClef) { $str = trim(afficheTexte($strSiteClef, 0)); if ($str === '' || $str === '*' . $strSiteClef . '*') { $str = fxBibTexte($strBibClef, 0); } return $str; } /** Libellé info_texte + bouton (?) si info_aide renseigné. */ function fxBibTexteAide($clef, $mem_echo = 1) { $str = fxBibTexte($clef, 0); $html = fxBibEsc($str) . fxBibAideButton($clef); if ($mem_echo) { echo $html; } return $html; } /** Titre d'en-tête de bloc (assignation, gestion…) + aide + doc overlay optionnel. */ function fxBibBlockHeader($clef, $docAnchorClef = '') { $html = '' . fxBibEsc(fxBibTexte($clef, 0)) . fxBibAideButton($clef); if ($docAnchorClef !== '') { $html .= fxDocRenderTrigger($docAnchorClef); $html .= fxAdminDocButton($docAnchorClef); } return $html . ''; } /** Pastille résumé dans la bande bleue (quantité dispo, séquences, etc.). */ function fxBibHeaderSummaryBadge($strText, $strVariant = '', $strTradClef = '') { $strClass = 'epr-header-summary'; if ($strVariant !== '') { $strClass .= ' epr-header-summary--' . preg_replace('/[^a-z0-9-]/', '', $strVariant); } $strInner = fxBibEsc($strText); if ($strTradClef !== '') { $strInner .= fxBibTradButton($strTradClef); } return '' . $strInner . ''; } /** Résumé gestion : quantité disponible. */ function fxBibGestionHeaderSummary($epr_id) { $arrQuantites = fxGetQuantites((int)$epr_id); $intDispo = (int)$arrQuantites['qte_restante']; $strLabel = fxBibSiteOrBibTexte('promoteur_qte_epr_qte', 'bib_v4_summary_dispo'); return fxBibHeaderSummaryBadge($strLabel . ' : ' . $intDispo, 'dispo', 'bib_v4_summary_dispo'); } /** Résumé assignation : nombre de séquences (+ auto si actif). */ function fxBibAssignHeaderSummary($intSeqCount, $blnAutoActive = false) { $html = ''; $intSeqCount = (int)$intSeqCount; if ($intSeqCount > 0) { if ($intSeqCount === 1) { $html .= fxBibHeaderSummaryBadge( fxBibTexte('bib_v4_summary_seq_one', 0), 'seq', 'bib_v4_summary_seq_one' ); } else { $html .= fxBibHeaderSummaryBadge( fxBibMsg('bib_v4_summary_seq_many', $intSeqCount), 'seq', 'bib_v4_summary_seq_many' ); } } else { $html .= fxBibHeaderSummaryBadge( fxBibTexte('bib_v4_summary_seq_empty', 0), 'seq-empty', 'bib_v4_summary_seq_empty' ); } if ($blnAutoActive) { $html .= fxBibHeaderSummaryBadge( fxBibTexte('bib_v4_auto_badge', 0), 'auto', 'bib_v4_auto_badge' ); } return $html; } /** Dossards encore disponibles dans une séquence (stats fxInfosBibRange). */ function fxBibRangeDispoFromRow(array $range) { $nb_total = (int)($range['nb_total_range'] ?? 0); $nb_utilises = (int)($range['nb_utilises'] ?? 0); return max(0, $nb_total - $nb_utilises); } /** Séquence utilisable pour l'assignation auto (au moins un dossard libre). */ function fxBibIsRangeAvailableForAuto($epr_id, $epr_bib_id) { $rows = fxInfosBibRange((int)$epr_id, (int)$epr_bib_id); if (empty($rows) || !is_array($rows[1] ?? null)) { return false; } if (fxBibRangeIsLocked($rows[1])) { return false; } return fxBibRangeDispoFromRow($rows[1]) > 0; } /** Séquence verrouillée (epr_bib_locked = 1) — plus de modification ni assignation. */ function fxBibRangeIsLocked(array $range) { return (int)($range['epr_bib_locked'] ?? 0) === 1; } /** Vérifie qu'aucune des séquences listées n'est verrouillée. */ function fxBibAssertRangesUnlocked($epr_id, $rangeIds) { global $objDatabase; $epr_id = (int)$epr_id; if ($epr_id <= 0 || empty($rangeIds) || !is_array($rangeIds)) { return ['success' => true]; } $ids = array_values(array_filter(array_map('intval', $rangeIds))); if (empty($ids)) { return ['success' => true]; } $strIds = implode(',', $ids); $sql = " SELECT COUNT(*) FROM inscriptions_epreuves_bib WHERE epr_id = $epr_id AND epr_bib_id IN ($strIds) AND epr_bib_locked = 1 "; if ((int)$objDatabase->fxGetVar($sql) > 0) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_range_locked')]; } return ['success' => true]; } /** Bascule le verrou d'une séquence (0 = ouvert, 1 = fermé). */ function fxBibSetRangeLocked($epr_bib_id, $locked, $epr_id = 0) { global $objDatabase; $epr_bib_id = (int)$epr_bib_id; $epr_id = (int)$epr_id; $locked = $locked ? 1 : 0; if ($epr_bib_id <= 0) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_id_invalid')]; } $sqlGet = " SELECT epr_id FROM inscriptions_epreuves_bib WHERE epr_bib_id = $epr_bib_id "; $rowEprId = (int)$objDatabase->fxGetVar($sqlGet); if ($rowEprId <= 0) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_range_not_found')]; } if ($epr_id > 0 && $rowEprId !== $epr_id) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_seq_invalid')]; } $objDatabase->fxQuery(" UPDATE inscriptions_epreuves_bib SET epr_bib_locked = $locked WHERE epr_bib_id = $epr_bib_id "); if ($locked === 1) { $objDatabase->fxQuery(" UPDATE inscriptions_epreuves_bib SET epr_bib_auto = 0 WHERE epr_bib_id = $epr_bib_id "); } return [ 'success' => true, 'epr_id' => $rowEprId, 'locked' => $locked === 1, ]; } /** Bouton cadenas (vert ouvert / rouge fermé) devant une séquence enregistrée. */ function fxBibRenderRangeLockButton(array $range, $epr_id = 0) { if ((int)($range['epr_bib_id'] ?? 0) <= 0) { return '
'; } $locked = fxBibRangeIsLocked($range); $strClass = $locked ? 'btn-bib-lock--closed' : 'btn-bib-lock--open'; $strIcon = $locked ? 'fa-lock' : 'fa-unlock'; $strTip = $locked ? 'bib_v4_tip_lock_closed' : 'bib_v4_tip_lock_open'; return '
'; } /** Badge « Assignation automatique » sur une ligne de séquence (epr_bib_auto = 1). */ function fxBibRenderRangeAutoBadge(array $range, $mode = 'assign') { if ($mode !== 'assign') { return ''; } if ((int)($range['epr_bib_id'] ?? 0) <= 0) { return ''; } if ((int)($range['epr_bib_auto'] ?? 0) !== 1) { return ''; } if (fxBibRangeIsLocked($range)) { return ''; } if (fxBibRangeDispoFromRow($range) <= 0) { return ''; } return '' . fxBibEsc(fxBibTexte('bib_v4_auto', 0)) . fxBibTradButton('bib_v4_auto') . ''; } /** Pastilles épreuve (solo/équipe, inscrits, avec dossard) — bande bleue colonne gauche. */ function fxBibEpreuveHeaderSummaries($tabEpreuve, $infoBib) { $html = ''; if ((int)$tabEpreuve['epr_equipe'] === 1) { $html .= fxBibHeaderSummaryBadge( fxBibSiteOrBibTexte('promoteur_epr_equipe', 'bib_v4_summary_team'), 'team', 'bib_v4_summary_team' ); } else { $html .= fxBibHeaderSummaryBadge( fxBibSiteOrBibTexte('promoteur_epr_solo', 'bib_v4_summary_solo'), 'solo', 'bib_v4_summary_solo' ); } $html .= '' . '' . (int)$infoBib['total'] . ' ' . fxBibSiteOrBibTexteTrad('promoteur_qte_epr_qte_ordered', 'bib_v4_summary_registered') . ''; $html .= '' . '' . (int)$infoBib['avec_bib'] . ' ' . fxBibSiteOrBibTexteTrad('promoteur_qte_epr_qte_orderedavec_bib', 'bib_v4_summary_with_bib') . ''; return $html; } /** En-tête bleu colonne gauche : titre de l'épreuve + pastilles (aligné visuellement avec la droite). */ function renderBibEpreuveIdentityHeader($tabEpreuve, $infoBib, $strLangue = 'fr') { $strCat = trim($tabEpreuve['epr_categorie_' . $strLangue] ?? ''); $strType = trim($tabEpreuve['epr_type_' . $strLangue] ?? ''); $strNom = trim($tabEpreuve['epr_nom_' . $strLangue] ?? ''); $intEprId = (int)($tabEpreuve['epr_id'] ?? 0); ob_start(); ?>
' . ''; } return ''; } /** Cellule d'en-tête de colonne séquence + aide optionnelle (info_texte peut être vide). */ function fxBibColHeader($clef) { $strLabel = fxBibTexte($clef, 0, true); $strClass = 'epr-col-header-label'; if ($strLabel === '') { $strClass .= ' epr-col-header-label--empty'; } return '' . fxBibEsc($strLabel) . fxBibAideButton($clef) . fxBibTradButton($clef) . ''; } /** Groupe action (bouton + ?) — $strClass ex. « epr-action-batch-group ». */ function fxBibActionGroupOpen($strClass, $blnVisible = true) { return ''; } function fxBibActionGroupClose() { return ''; } /** Ouvre le segment bouton + ? collés (option A — rangée d'actions). */ function fxBibBtnAideSegmentOpen($strExtraClass = '') { $strClass = 'epr-btn-aide-segment'; if ($strExtraClass !== '') { $strClass .= ' ' . preg_replace('/[^a-z0-9 _-]/', '', $strExtraClass); } return ''; } function fxBibBtnAideSegmentClose($clef = '') { $html = ''; if ($clef !== '') { $html .= fxBibTradButton($clef); } return $html . ''; } /** * Bloc gestion épreuve (quantités lecture seule + liste d'attente). * Pas de bouton OK — les quantités ne sont plus modifiables depuis cet écran. */ function renderBibGestionEpreuve($epr_id, $int_eve_id, $strLangue) { $epr_id = (int)$epr_id; $int_eve_id = (int)$int_eve_id; $arrQuantites = fxGetQuantites($epr_id); $QCheckin = fxGetCheckinqte($epr_id); $nbSurListeA = fx_liste_attente_nombre_surliste($epr_id, 1); $nbSurListe = fx_liste_attente_nombre_surliste($epr_id); $intNbSurListeA = ($nbSurListeA !== false && $nbSurListeA > 0) ? (int)$nbSurListeA : 0; $intNbSurListe = ($nbSurListe !== false && $nbSurListe > 0) ? (int)$nbSurListe : 0; ob_start(); ?>
0 ? $intNbSurListeA : '—'; ?>
0 ? $intNbSurListe : '—'; ?>
0 && $intEnd >= $intStart) { $intQty = $intEnd - $intStart + 1; } return [ 'qty' => $intQty, 'start' => $intStart, 'end' => $intEnd, 'has_values' => ($intId > 0 && $intStart > 0 && $intEnd >= $intStart), ]; } /** MSIN-4429 — Colonne « ou » entre Qté et Fin. */ function fxBibRenderRangeOrCell() { ob_start(); ?>
0; ob_start(); ?>
$intBibId, 'start' => (int)$row['epr_bib_start'], 'end' => (int)$row['epr_bib_finish'], 'dispo' => $intDispo, ]; } return $out; } /** MSIN-4436 — Vérifie épreuve solo de l'événement (batch global). */ function fxBibAssertSoloEpreuveForGlobalBatch($epr_id, $int_eve_id) { global $objDatabase; $epr_id = (int)$epr_id; $int_eve_id = (int)$int_eve_id; $row = $objDatabase->fxGetRow(" SELECT epr_id, eve_id, epr_equipe FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1 "); if (!$row || (int)$row['eve_id'] !== $int_eve_id) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')]; } if ((int)$row['epr_equipe'] === 1) { return ['success' => false, 'message' => fxBibMsg('bib_v4_global_batch_team_excluded')]; } return ['success' => true]; } /** MSIN-4436 — Plans batch global validés [{epr_id, ranges[]}]. */ function fxBibParseGlobalBatchPlans($plans, $int_eve_id) { if (!is_array($plans)) { return []; } $out = []; foreach ($plans as $plan) { $epr_id = (int)($plan['epr_id'] ?? 0); $ranges = $plan['ranges'] ?? []; if ($epr_id <= 0 || !is_array($ranges)) { continue; } $check = fxBibAssertSoloEpreuveForGlobalBatch($epr_id, $int_eve_id); if (!$check['success']) { continue; } $ranges = array_values(array_filter(array_map('intval', $ranges))); if (empty($ranges)) { continue; } $lockCheck = fxBibAssertRangesUnlocked($epr_id, $ranges); if (!$lockCheck['success']) { continue; } $out[] = [ 'epr_id' => $epr_id, 'ranges' => $ranges, ]; } return $out; } /** * MSIN-4436 — Coquille assignation globale (aucun calcul séquence au chargement page). */ function renderBibGlobalBatchPanelShell($int_eve_id, $tabEpreuves, $strLangue) { $int_eve_id = (int)$int_eve_id; $intSolo = 0; foreach ($tabEpreuves as $epr) { if ((int)($epr['epr_equipe'] ?? 0) !== 1) { $intSolo++; } } if ($intSolo < 2) { return ''; } ob_start(); ?>
$epr, 'ranges' => $tabRanges, ]; } if (count($tabSolo) < 2) { if (empty($tabSolo)) { return ''; } ob_start(); ?>

fxGetResults($sqlEpreuves); $sqlBibAssignments = "SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri"; $tabBibAssignments = $objDatabase->fxGetResults($sqlBibAssignments); ?>

>
fxGetResults($sqlBibRanges); // MSIN-4436 — Chargement page : stats séquences sans trous/doublons (calcul complet en AJAX refresh). $tabBibStats = fxInfosBibRange(intval($tabEpreuves[$i]['epr_id']), 0, false); $infoBib = fxInfosBibEpreuve(intval($tabEpreuves[$i]['epr_id'])); // MSIN-4379 — Étape 2 : détecte si l'auto est actif (au moins une séquence epr_bib_auto=1). // Prochain tour : étape 6–7 (assignation à l'achat). $blnAutoActive = fxIsBibAutoActive((int)$tabEpreuves[$i]['epr_id']); ?>
0); if ($teamMode <= 0) { $teamMode = 1; } ?>
0, p2.pec_id, p2.par_id)) FROM resultats_participants p2 WHERE p2.epr_id = ($strEprIdExpr) AND $strBibP2 = ($strBibNumExpr) AND p2.is_cancelled = 0 ) ELSE ( SELECT COUNT(*) FROM resultats_participants p2 WHERE p2.epr_id = ($strEprIdExpr) AND $strBibP2 = ($strBibNumExpr) AND p2.is_cancelled = 0 ) END)"; } /** SQL — vrai doublon (anomalie), hors partage légitime entre coéquipiers (mode équipe 3). */ function fxBibSqlIsBibDuplicateAnomaly($strEprIdExpr, $strBibNumExpr) { return fxBibSqlDuplicateUnitCount($strEprIdExpr, $strBibNumExpr) . ' > 1'; } function fxInfosBibRange($epr_id = 0, $epr_bib_id = 0, $blnIncludeGaps = true){ global $objDatabase, $vDomaine; static $memCache = []; $epr_id = (int)$epr_id; $epr_bib_id = (int)$epr_bib_id; $blnIncludeGaps = ($blnIncludeGaps !== false); $strCacheKey = $epr_id . ':' . $epr_bib_id . ':' . ($blnIncludeGaps ? 'g' : 'l'); if (array_key_exists($strCacheKey, $memCache)) { return $memCache[$strCacheKey]; } $where = []; if ($epr_id > 0) { $where[] = "b.epr_id = " . $epr_id; } if ($epr_bib_id > 0) { $where[] = "b.epr_bib_id = " . $epr_bib_id; } if (empty($where)) { $memCache[$strCacheKey] = []; return $memCache[$strCacheKey]; } $where_sql = implode(' AND ', $where); $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $sqlBibNumRp = fxBibSqlNoBibUnsigned('rp.no_bib'); if ($blnIncludeGaps) { $sqlGapCols = " ( SELECT COUNT(*) FROM ( SELECT (n1.N + n2.N * 10 + n3.N * 100 + n4.N * 1000) AS num FROM (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n1 CROSS JOIN (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n2 CROSS JOIN (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n3 CROSS JOIN (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n4 ) t WHERE t.num BETWEEN b.epr_bib_start AND IFNULL(( SELECT MAX($sqlBibNumRp) FROM resultats_participants rp WHERE rp.epr_id = b.epr_id AND $sqlBibNumRp BETWEEN b.epr_bib_start AND b.epr_bib_finish ), b.epr_bib_start - 1) AND t.num NOT IN ( SELECT $sqlBibNumRp FROM resultats_participants rp WHERE rp.epr_id = b.epr_id AND $sqlBibNumRp > 0 ) ) AS nb_trous, ( SELECT GROUP_CONCAT(t.num ORDER BY t.num SEPARATOR ',') FROM ( SELECT (n1.N + n2.N * 10 + n3.N * 100 + n4.N * 1000) AS num FROM (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n1 CROSS JOIN (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n2 CROSS JOIN (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n3 CROSS JOIN (SELECT 0 N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n4 ) t WHERE t.num BETWEEN b.epr_bib_start AND IFNULL(( SELECT MAX($sqlBibNumRp) FROM resultats_participants rp WHERE rp.epr_id = b.epr_id AND $sqlBibNumRp BETWEEN b.epr_bib_start AND b.epr_bib_finish ), b.epr_bib_start - 1) AND t.num NOT IN ( SELECT $sqlBibNumRp FROM resultats_participants rp WHERE rp.epr_id = b.epr_id AND $sqlBibNumRp > 0 ) ) AS liste_trous, ( SELECT GROUP_CONCAT(DISTINCT $sqlBibNumRp ORDER BY $sqlBibNumRp SEPARATOR ',') FROM resultats_participants rp WHERE rp.epr_id = b.epr_id AND rp.is_cancelled = 0 AND $sqlBibNumRp BETWEEN b.epr_bib_start AND b.epr_bib_finish AND " . fxBibSqlIsBibDuplicateAnomaly('rp.epr_id', $sqlBibNumRp) . " ) AS liste_doublons"; } else { // MSIN-4436 — Chargement page : dispo/utilisés seulement (trous/doublons via refresh AJAX). $sqlGapCols = " 0 AS nb_trous, '' AS liste_trous, '' AS liste_doublons"; } $sqlBibStats = " SELECT b.epr_bib_id, b.epr_id, b.epr_bib_start, b.epr_bib_finish, b.epr_bib_auto, b.epr_bib_locked, COUNT(DISTINCT $sqlBibNumP) AS nb_utilises, MAX($sqlBibNumP) AS dernier_bib, (b.epr_bib_finish - b.epr_bib_start + 1) AS nb_total_range, $sqlGapCols FROM inscriptions_epreuves_bib b LEFT JOIN resultats_participants p ON p.epr_id = b.epr_id AND p.is_cancelled = 0 AND $sqlBibNumP BETWEEN b.epr_bib_start AND b.epr_bib_finish AND $sqlBibNumP > 0 WHERE $where_sql AND b.epr_bib_start IS NOT NULL AND b.epr_bib_finish IS NOT NULL GROUP BY b.epr_bib_id, b.epr_id, b.epr_bib_start, b.epr_bib_finish, b.epr_bib_auto, b.epr_bib_locked ORDER BY b.epr_bib_start "; $tabResult = $objDatabase->fxGetResults($sqlBibStats); $memCache[$strCacheKey] = is_array($tabResult) ? $tabResult : []; return $memCache[$strCacheKey]; } /** MSIN-4379 — Libellé court épreuve pour le dashboard anomalies. */ function fxBibAnomalyEprLabel(array $tabEpreuve, $strLangue = 'fr') { $str = fxBibEpreuveDisplayName($tabEpreuve, $strLangue); $strNom = trim($tabEpreuve['epr_nom_' . $strLangue] ?? ''); if ($strNom !== '' && stripos($str, $strNom) === false) { $str .= ' — ' . $strNom; } return $str; } /** SQL — l'épreuve a au moins une séquence de dossards configurée. */ function fxBibSqlEpreuveHasBibRanges($strEprIdExpr) { return "EXISTS ( SELECT 1 FROM inscriptions_epreuves_bib b0 WHERE b0.epr_id = ($strEprIdExpr) AND b0.epr_bib_start IS NOT NULL AND b0.epr_bib_finish IS NOT NULL )"; } /** * MSIN-4379 — Regroupe les lignes SQL de fxBibAnomalyDuplicateBibs par séquence + no_bib. * * @return array> */ function fxBibAnomalyGroupDuplicateRows(array $rows, $strLangue = 'fr') { $grouped = []; foreach ($rows as $row) { $intRangeId = (int)$row['epr_bib_id']; $key = ($intRangeId > 0 ? $intRangeId : (int)$row['epr_id']) . '-' . (int)$row['no_bib']; if (!isset($grouped[$key])) { $grouped[$key] = [ 'epr_id' => (int)$row['epr_id'], 'epr_label' => fxBibAnomalyEprLabel($row, $strLangue), 'range_id' => $intRangeId, 'range_start' => (int)$row['epr_bib_start'], 'range_end' => (int)$row['epr_bib_finish'], 'no_bib' => (int)$row['no_bib'], 'participants' => [], ]; } $grouped[$key]['participants'][] = [ 'par_id' => (int)$row['par_id'], 'par_prenom' => trim($row['par_prenom'] ?? ''), 'par_nom' => trim($row['par_nom'] ?? ''), ]; } return array_values($grouped); } /** * MSIN-4379 — Dossards en double (même epr_id, même no_bib, >1 unité active). * Couvre les séquences configurées et les épreuves sans séquence (saisie manuelle). * * @return array> */ function fxBibAnomalyDuplicateBibs($int_eve_id, $strLangue = 'fr') { global $objDatabase; $int_eve_id = (int)$int_eve_id; if ($int_eve_id <= 0) { return []; } $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $sqlInRange = " SELECT b.epr_bib_id, b.epr_id, b.epr_bib_start, b.epr_bib_finish, e.epr_nom_fr, e.epr_nom_en, e.epr_type_fr, e.epr_type_en, e.epr_categorie_fr, e.epr_categorie_en, e.epr_actif, $sqlBibNumP AS no_bib, p.par_id, p.par_prenom, p.par_nom FROM inscriptions_epreuves_bib b INNER JOIN inscriptions_epreuves e ON e.epr_id = b.epr_id INNER JOIN resultats_participants p ON p.epr_id = b.epr_id AND p.is_cancelled = 0 AND $sqlBibNumP BETWEEN b.epr_bib_start AND b.epr_bib_finish AND $sqlBibNumP > 0 WHERE e.eve_id = $int_eve_id AND b.epr_bib_start IS NOT NULL AND b.epr_bib_finish IS NOT NULL AND " . fxBibSqlIsBibDuplicateAnomaly('b.epr_id', $sqlBibNumP) . " ORDER BY b.epr_id, b.epr_bib_start, $sqlBibNumP, p.par_nom, p.par_prenom "; $sqlNoRange = " SELECT 0 AS epr_bib_id, p.epr_id, 0 AS epr_bib_start, 0 AS epr_bib_finish, e.epr_nom_fr, e.epr_nom_en, e.epr_type_fr, e.epr_type_en, e.epr_categorie_fr, e.epr_categorie_en, e.epr_actif, $sqlBibNumP AS no_bib, p.par_id, p.par_prenom, p.par_nom FROM resultats_participants p INNER JOIN inscriptions_epreuves e ON e.epr_id = p.epr_id WHERE e.eve_id = $int_eve_id AND p.is_cancelled = 0 AND $sqlBibNumP > 0 AND NOT " . fxBibSqlEpreuveHasBibRanges('p.epr_id') . " AND " . fxBibSqlIsBibDuplicateAnomaly('p.epr_id', $sqlBibNumP) . " ORDER BY p.epr_id, $sqlBibNumP, p.par_nom, p.par_prenom "; $rows = $objDatabase->fxGetResults($sqlInRange); if (!is_array($rows)) { $rows = []; } $rowsNoRange = $objDatabase->fxGetResults($sqlNoRange); if (is_array($rowsNoRange) && !empty($rowsNoRange)) { $rows = array_merge($rows, $rowsNoRange); } if (empty($rows)) { return []; } return fxBibAnomalyGroupDuplicateRows($rows, $strLangue); } /** * MSIN-4379 — Dossards orphelins : numéro dans une séquence mais plus valide pour l'épreuve * (coureur annulé, ou dossard conservé après changement d'épreuve). * @return array> */ function fxBibAnomalyOrphanBibs($int_eve_id, $strLangue = 'fr') { global $objDatabase; $int_eve_id = (int)$int_eve_id; if ($int_eve_id <= 0) { return []; } $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $sql = " SELECT b.epr_bib_id, b.epr_id, b.epr_bib_start, b.epr_bib_finish, e.epr_nom_fr, e.epr_nom_en, e.epr_type_fr, e.epr_type_en, e.epr_categorie_fr, e.epr_categorie_en, e.epr_actif, $sqlBibNumP AS no_bib, p.par_id, p.par_prenom, p.par_nom, p.epr_id AS participant_epr_id, p.is_cancelled, CASE WHEN p.epr_id <> b.epr_id THEN 'transferred' WHEN p.is_cancelled = 1 THEN 'cancelled' ELSE 'other' END AS orphan_type FROM inscriptions_epreuves_bib b INNER JOIN inscriptions_epreuves e ON e.epr_id = b.epr_id INNER JOIN resultats_participants p ON p.eve_id = e.eve_id AND $sqlBibNumP > 0 AND $sqlBibNumP BETWEEN b.epr_bib_start AND b.epr_bib_finish WHERE e.eve_id = $int_eve_id AND b.epr_bib_start IS NOT NULL AND b.epr_bib_finish IS NOT NULL AND ( (p.epr_id <> b.epr_id) OR (p.epr_id = b.epr_id AND p.is_cancelled = 1) ) ORDER BY b.epr_id, b.epr_bib_start, $sqlBibNumP, p.par_nom, p.par_prenom "; $rows = $objDatabase->fxGetResults($sql); if (!is_array($rows) || empty($rows)) { return []; } $out = []; foreach ($rows as $row) { $participantEprId = (int)$row['participant_epr_id']; $participantLabel = ''; if ($participantEprId > 0) { $tabHolderEpr = $objDatabase->fxGetRow(" SELECT epr_id, epr_nom_fr, epr_nom_en, epr_type_fr, epr_type_en, epr_categorie_fr, epr_categorie_en, epr_actif FROM inscriptions_epreuves WHERE epr_id = $participantEprId LIMIT 1 "); if (is_array($tabHolderEpr)) { $participantLabel = fxBibAnomalyEprLabel($tabHolderEpr, $strLangue); } } $out[] = [ 'epr_id' => (int)$row['epr_id'], 'epr_label' => fxBibAnomalyEprLabel($row, $strLangue), 'range_id' => (int)$row['epr_bib_id'], 'range_start' => (int)$row['epr_bib_start'], 'range_end' => (int)$row['epr_bib_finish'], 'no_bib' => (int)$row['no_bib'], 'orphan_type' => $row['orphan_type'], 'participant_epr_id' => $participantEprId, 'participant_epr_label'=> $participantLabel, 'par_id' => (int)$row['par_id'], 'par_prenom' => trim($row['par_prenom'] ?? ''), 'par_nom' => trim($row['par_nom'] ?? ''), ]; } return $out; } /** * MSIN-4379 — Inscriptions sans dossard : auto-assign échoué (séquences épuisées). * Lit inscriptions_evt_erreur (type bib_auto_miss), purge les lignes déjà corrigées. * @return array> */ function fxBibAnomalyAutoMissBibs($int_eve_id, $strLangue = 'fr') { global $objDatabase; $int_eve_id = (int)$int_eve_id; if ($int_eve_id <= 0 || !fxEvtErreurTableReady()) { return []; } $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $sqlPurge = " UPDATE inscriptions_evt_erreur e INNER JOIN resultats_participants p ON p.par_id = e.par_id AND p.epr_id = e.epr_id SET e.evt_err_statut = 'resolu', e.evt_err_resolved = NOW() WHERE e.eve_id = $int_eve_id AND e.evt_err_type = 'bib_auto_miss' AND e.evt_err_statut = 'ouvert' AND ( p.is_cancelled = 1 OR $sqlBibNumP > 0 ) "; $objDatabase->fxQuery($sqlPurge); $sql = " SELECT e.evt_err_id, e.eve_id, e.epr_id, e.par_id, e.pec_id, e.no_commande, e.no_panier, e.com_id, e.evt_err_created, p.par_prenom, p.par_nom, ep.epr_nom_fr, ep.epr_nom_en, ep.epr_type_fr, ep.epr_type_en, ep.epr_categorie_fr, ep.epr_categorie_en, ep.epr_actif FROM inscriptions_evt_erreur e INNER JOIN resultats_participants p ON p.par_id = e.par_id AND p.epr_id = e.epr_id INNER JOIN inscriptions_epreuves ep ON ep.epr_id = e.epr_id WHERE e.eve_id = $int_eve_id AND e.evt_err_type = 'bib_auto_miss' AND e.evt_err_statut = 'ouvert' AND p.is_cancelled = 0 AND ($sqlBibNumP = 0 OR p.no_bib IS NULL OR p.no_bib = '' OR p.no_bib = '0') ORDER BY e.evt_err_created DESC, e.epr_id, p.par_nom, p.par_prenom "; $rows = $objDatabase->fxGetResults($sql); if (!is_array($rows) || empty($rows)) { return []; } $items = []; foreach ($rows as $row) { $items[] = [ 'evt_err_id' => (int)$row['evt_err_id'], 'epr_id' => (int)$row['epr_id'], 'epr_label' => fxBibAnomalyEprLabel($row, $strLangue), 'par_id' => (int)$row['par_id'], 'par_prenom' => trim($row['par_prenom'] ?? ''), 'par_nom' => trim($row['par_nom'] ?? ''), 'no_commande' => trim($row['no_commande'] ?? ''), 'evt_err_created' => trim($row['evt_err_created'] ?? ''), ]; } return $items; } /** * MSIN-4379 — Dossards assignés hors de toute séquence configurée pour l'épreuve. * Couvre la saisie manuelle (fiche coureur) ou tout assignement ne passant pas par les plages. * Inclut les épreuves sans aucune séquence (dossards uniques seulement — les doublons vont dans dupes). * * @return array> */ function fxBibAnomalyOutOfRangeBibs($int_eve_id, $strLangue = 'fr') { global $objDatabase; $int_eve_id = (int)$int_eve_id; if ($int_eve_id <= 0) { return []; } $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $sql = " SELECT p.par_id, p.par_prenom, p.par_nom, p.epr_id, $sqlBibNumP AS no_bib, e.epr_nom_fr, e.epr_nom_en, e.epr_type_fr, e.epr_type_en, e.epr_categorie_fr, e.epr_categorie_en, e.epr_actif FROM resultats_participants p INNER JOIN inscriptions_epreuves e ON e.epr_id = p.epr_id WHERE e.eve_id = $int_eve_id AND p.is_cancelled = 0 AND $sqlBibNumP > 0 AND ( ( " . fxBibSqlEpreuveHasBibRanges('p.epr_id') . " AND NOT EXISTS ( SELECT 1 FROM inscriptions_epreuves_bib b WHERE b.epr_id = p.epr_id AND b.epr_bib_start IS NOT NULL AND b.epr_bib_finish IS NOT NULL AND $sqlBibNumP BETWEEN b.epr_bib_start AND b.epr_bib_finish ) ) OR ( NOT " . fxBibSqlEpreuveHasBibRanges('p.epr_id') . " AND NOT " . fxBibSqlIsBibDuplicateAnomaly('p.epr_id', $sqlBibNumP) . " ) ) ORDER BY p.epr_id, $sqlBibNumP, p.par_nom, p.par_prenom "; $rows = $objDatabase->fxGetResults($sql); if (!is_array($rows) || empty($rows)) { return []; } $items = []; foreach ($rows as $row) { $items[] = [ 'epr_id' => (int)$row['epr_id'], 'epr_label' => fxBibAnomalyEprLabel($row, $strLangue), 'par_id' => (int)$row['par_id'], 'par_prenom' => trim($row['par_prenom'] ?? ''), 'par_nom' => trim($row['par_nom'] ?? ''), 'no_bib' => (int)$row['no_bib'], ]; } return $items; } /** MSIN-4379 — Agrège toutes les anomalies dossards pour un événement. */ function fxBibCollectAnomalies($int_eve_id, $strLangue = 'fr') { return [ 'dupes' => fxBibAnomalyDuplicateBibs($int_eve_id, $strLangue), 'out_of_range' => fxBibAnomalyOutOfRangeBibs($int_eve_id, $strLangue), 'orphans' => fxBibAnomalyOrphanBibs($int_eve_id, $strLangue), 'auto_miss' => fxBibAnomalyAutoMissBibs($int_eve_id, $strLangue), ]; } function fxBibAnomalyTotalCount(array $tabAnomalies) { $intTotal = 0; foreach (['dupes', 'out_of_range', 'orphans', 'auto_miss'] as $strKey) { if (!empty($tabAnomalies[$strKey]) && is_array($tabAnomalies[$strKey])) { $intTotal += count($tabAnomalies[$strKey]); } } return $intTotal; } /** * MSIN-4436 — Coquille anomalies au chargement page (détail via AJAX). * Évite 4 requêtes lourdes avant le premier affichage des épreuves. */ function renderBibAnomaliesPanelShell($int_eve_id, $strLangue = 'fr') { global $vDomaine; $int_eve_id = (int)$int_eve_id; $strWait = fxBibTexte('bib_v4_js_loader_wait', 0); if ($strWait === '' || $strWait === 'bib_v4_js_loader_wait') { $strWait = ($strLangue === 'en') ? 'Loading...' : 'Chargement...'; } $strRunnerSrc = $vDomaine . '/images/ms1-runner-loader.gif?v=' . _VERSION_CODE; ob_start(); ?> 0; ob_start(); ?> fxGetVar($sql) > 0; } /** MSIN-4379 — Refuse l'activation auto tant qu'il reste des inscriptions sans dossard. */ function fxBibAssertAllBibsAssignedForAuto($epr_id) { $info = fxInfosBibEpreuve(intval($epr_id)); $nbPending = (int)($info['a_assigner'] ?? 0); if ($nbPending > 0) { return [ 'success' => false, 'message' => fxBibMsg('bib_v4_ajax_auto_pending_bibs', $nbPending), ]; } return ['success' => true]; } /** * MSIN-4379 — Étape 2 * Enregistre la config auto : remet toutes les séquences à 0, puis marque * epr_bib_auto = 1 sur les epr_bib_id choisis. Si $active = false, tout désactive. * Prochain tour : étape 6 lira ces séquences pour fxAssignAutoBibForParticipant(). */ function fxSaveBibAutoConfig($epr_id, $ranges, $active = true) { global $objDatabase; $epr_id = intval($epr_id); $active = (bool)$active; if ($epr_id <= 0) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')]; } $objDatabase->fxQuery(" UPDATE inscriptions_epreuves_bib SET epr_bib_auto = 0 WHERE epr_id = $epr_id "); if (!$active) { return ['success' => true, 'auto_active' => false]; } $pendingCheck = fxBibAssertAllBibsAssignedForAuto($epr_id); if (!$pendingCheck['success']) { return $pendingCheck; } if (empty($ranges) || !is_array($ranges)) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_no_seq_selected')]; } $ids = array_values(array_filter(array_map('intval', $ranges))); if (empty($ids)) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_no_seq_selected')]; } $strIds = implode(',', $ids); $sqlCheck = " SELECT COUNT(*) FROM inscriptions_epreuves_bib WHERE epr_id = $epr_id AND epr_bib_id IN ($strIds) "; $nbValid = (int)$objDatabase->fxGetVar($sqlCheck); if ($nbValid !== count($ids)) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_seq_invalid')]; } foreach ($ids as $bibId) { if (!fxBibIsRangeAvailableForAuto($epr_id, $bibId)) { return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_auto_seq_full')]; } } $lockCheck = fxBibAssertRangesUnlocked($epr_id, $ids); if (!$lockCheck['success']) { return $lockCheck; } $objDatabase->fxQuery(" UPDATE inscriptions_epreuves_bib SET epr_bib_auto = 1 WHERE epr_id = $epr_id AND epr_bib_id IN ($strIds) "); return ['success' => true, 'auto_active' => true]; } /** * MSIN-4379 — Étape 6 * Liste des epr_bib_id marqués epr_bib_auto = 1 pour une épreuve. */ function fxGetAutoBibRangeIds($epr_id) { global $objDatabase; $epr_id = intval($epr_id); if ($epr_id <= 0 || !fxIsBibAutoActive($epr_id)) { return []; } $sql = " SELECT epr_bib_id FROM inscriptions_epreuves_bib WHERE epr_id = $epr_id AND epr_bib_auto = 1 AND epr_bib_locked = 0 ORDER BY epr_bib_start "; $rows = $objDatabase->fxGetResults($sql); $ids = []; if (is_array($rows)) { foreach ($rows as $r) { $id = (int)($r['epr_bib_id'] ?? 0); if ($id > 0) { $ids[] = $id; } } } return $ids; } /** * MSIN-4379 — Étape 6 * Charge un participant resultats pour l'assignation auto (même jointures que le batch). */ function fxLoadParticipantForAutoBib($epr_id, $par_id) { global $objDatabase; $epr_id = intval($epr_id); $par_id = intval($par_id); if ($epr_id <= 0 || $par_id <= 0) { return null; } $sql = " SELECT p.*, p.pec_id, c.pec_id_original, c.pec_nom_equipe, c.no_equipe 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.par_id = $par_id AND p.is_cancelled = 0 LIMIT 1 "; return $objDatabase->fxGetRow($sql); } /** * MSIN-4379 — Étape 6 * Assigne un dossard à un participant à l'achat (pools epr_bib_auto = 1). * Réutilise fxFindNextBatchBib / fxApplyBatchParticipantBib et la logique équipe du batch. */ function fxAssignAutoBibForParticipant($epr_id, $par_id) { global $objDatabase; $epr_id = intval($epr_id); $par_id = intval($par_id); if ($epr_id <= 0 || $par_id <= 0) { return ['success' => false, 'message' => 'paramètres invalides']; } if (!fxIsBibAutoActive($epr_id)) { return ['success' => false, 'skipped' => true, 'message' => 'auto inactif']; } $tabRanges = fxGetRangesForBatchAssign($epr_id, fxGetAutoBibRangeIds($epr_id)); if (empty($tabRanges)) { return ['success' => false, 'message' => 'aucune plage auto']; } $p = fxLoadParticipantForAutoBib($epr_id, $par_id); if (!$p) { return ['success' => false, 'message' => 'participant introuvable']; } if (in_array((int)$p['rol_id'], [3, 4], true)) { return ['success' => false, 'skipped' => true, 'message' => 'rôle exclu']; } $currentBib = trim((string)($p['no_bib'] ?? '')); if ($currentBib !== '' && $currentBib !== '0') { return [ 'success' => true, 'skipped' => true, 'no_bib' => (int)$currentBib, ]; } $sqlEpreuve = " SELECT epr_equipe, epr_bib_team_mode FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1 "; $tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve); $isTeamEvent = $tabEpreuve && (int)$tabEpreuve['epr_equipe'] === 1; $teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1); if ($teamMode <= 0) { $teamMode = 1; } $teamKey = fxGetBatchTeamKey($p); $foundBib = null; $teamNumber = 0; $usedBib = []; if ($isTeamEvent && $teamMode === 3 && $teamKey > 0) { $sqlTeamBib = " SELECT no_bib FROM resultats_participants WHERE epr_id = $epr_id AND pec_id = $teamKey AND is_cancelled = 0 AND no_bib IS NOT NULL AND no_bib <> '' AND no_bib <> 0 AND par_id <> $par_id LIMIT 1 "; $existingBib = (int)$objDatabase->fxGetVar($sqlTeamBib); if ($existingBib > 0) { $foundBib = $existingBib; $teamNumber = $existingBib; } } if ($foundBib === null) { $findTeamMode = $isTeamEvent ? $teamMode : 1; $foundBib = fxFindNextBatchBib($epr_id, $tabRanges, 'execute', $usedBib, $findTeamMode); } if ($foundBib === null) { if (function_exists('fxcreer_log')) { fxcreer_log('MSIN-4379: aucun dossard libre (epr_id=' . $epr_id . ', par_id=' . $par_id . ')'); } if ($p && function_exists('fxEvtErreurOuvrir')) { fxEvtErreurOuvrir('bib_auto_miss', [ 'eve_id' => (int)($p['eve_id'] ?? 0), 'epr_id' => $epr_id, 'par_id' => $par_id, 'pec_id' => (int)($p['pec_id'] ?? 0), 'no_commande' => trim((string)($p['no_commande'] ?? '')), 'no_panier' => trim((string)($p['no_panier'] ?? '')), 'com_id' => (int)($p['com_id'] ?? 0), ]); } return ['success' => false, 'message' => 'aucun dossard disponible']; } fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib); if ($isTeamEvent && $teamKey > 0) { $updatedTeams = []; if ($teamMode === 3) { fxApplyBatchTeamNumber($epr_id, $teamKey, $foundBib, $updatedTeams); } else { $sqlEquipe = " SELECT no_equipe FROM resultats_epreuves_commandees WHERE pec_id_original = $teamKey AND epr_id = $epr_id LIMIT 1 "; $teamNumber = (int)$objDatabase->fxGetVar($sqlEquipe); if ($teamNumber <= 0) { $sqlMaxTeam = " SELECT MAX(CAST(no_equipe AS UNSIGNED)) FROM resultats_epreuves_commandees WHERE epr_id = $epr_id "; $teamNumber = (int)$objDatabase->fxGetVar($sqlMaxTeam) + 1; } fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams); } } return [ 'success' => true, 'no_bib' => (int)$foundBib, ]; } function fxInfosBibEpreuve($epr_id){ global $objDatabase; static $memCache = []; $epr_id = intval($epr_id); if ($epr_id <= 0) { return [ 'total' => 0, 'avec_bib' => 0, 'sans_bib' => 0 ]; } if (isset($memCache[$epr_id])) { return $memCache[$epr_id]; } $sqlEpreuve = " SELECT epr_equipe, epr_bib_team_mode FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1 "; $tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve); $blnTeamOneBib = $tabEpreuve && (int)$tabEpreuve['epr_equipe'] === 1 && (int)($tabEpreuve['epr_bib_team_mode'] ?? 1) === 3; if ($blnTeamOneBib) { // MSIN-4432 — aligné sur fxGetQuantites / fxCountBatchAssignUnits : une équipe = une unité. $sql = " SELECT COUNT(DISTINCT p.pec_id) AS total, COUNT(DISTINCT CASE WHEN p.no_bib IS NOT NULL AND p.no_bib > 0 THEN p.pec_id ELSE NULL END) AS avec_bib FROM resultats_participants p WHERE p.epr_id = $epr_id AND p.is_cancelled = 0 AND p.pec_id > 0 "; $row = $objDatabase->fxGetRow($sql); $intTotal = (int)($row['total'] ?? 0); $intAvecBib = (int)($row['avec_bib'] ?? 0); } else { $sql = " SELECT COUNT(*) AS total, SUM(CASE WHEN no_bib IS NOT NULL AND no_bib > 0 THEN 1 ELSE 0 END) AS avec_bib FROM resultats_participants WHERE epr_id = $epr_id AND is_cancelled = 0 "; $row = $objDatabase->fxGetRow($sql); $intTotal = (int)($row['total'] ?? 0); $intAvecBib = (int)($row['avec_bib'] ?? 0); } $info = [ 'total' => $intTotal, 'avec_bib' => $intAvecBib, 'sans_bib' => max(0, $intTotal - $intAvecBib), 'a_assigner' => fxCountBatchAssignUnits($epr_id) ]; $memCache[$epr_id] = $info; return $info; } function renderBibRanges($tabBibRanges, $epr_id = 0, $mode = 'assign') { //print_rsl($tabBibRanges); if (!is_array($tabBibRanges)) { $tabBibRanges = []; } if ((int)$epr_id <= 0 && !empty($tabBibRanges[0]['epr_id'])) { $epr_id = (int)$tabBibRanges[0]['epr_id']; } ob_start(); ?>
0) { ?>
0) { ?>
> > > 0) { ?>
0 && (int)$range['epr_bib_id'] > 0 )) { $showCheckbox = true; } if (!$blnRangeLocked && ( $mode === 'reset' && (int)$range['nb_utilises'] > 0 && (int)$range['epr_bib_id'] > 0 )) { $showCheckbox = true; } // MSIN-4379 — Étape 2 : mode « auto » — séquences avec dossards disponibles seulement. if (!$blnRangeLocked && ( $mode === 'auto' && $mem_dispo > 0 && (int)$range['epr_bib_id'] > 0 )) { $showCheckbox = true; } ?> checked>
0; if ($hasRange) { $sqlRange = " SELECT * FROM inscriptions_epreuves_bib WHERE epr_bib_id = " . intval($range_id); $range = $objDatabase->fxGetRow($sqlRange); if (!$range) { return '
' . fxBibTexteTrad('bib_v4_view_range_not_found', 0) . '
'; } $start = (int)$range['epr_bib_start']; $end = (int)$range['epr_bib_finish']; } // ===================== // 2. GET EPREUVE // ===================== $sqlEpreuve = " SELECT * FROM inscriptions_epreuves WHERE epr_id = " . intval($epr_id); $tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve); if (!$tabEpreuve) { return '
' . fxBibTexteTrad('bib_v4_view_epreuve_not_found', 0) . '
'; } // ===================== // 3. GET PARTICIPANTS (DB ou SIMULATION) // ===================== if (!empty($data)) { $tabParticipants = $data; } else { // DB // 👉 mode normal (DB) $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $strWhereView = "p.epr_id = " . intval($epr_id); if ($hasRange) { $strWhereView .= " AND $sqlBibNumP > 0 AND $sqlBibNumP BETWEEN $start AND $end"; } else { $strWhereView .= " AND ( (COALESCE(p.is_cancelled, 0) = 0 AND COALESCE(c.is_cancelled, 0) = 0) OR $sqlBibNumP > 0 )"; } $sqlParticipants = " SELECT p.*, c.pec_nom_equipe, c.no_equipe, c.is_cancelled AS pec_is_cancelled 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 $strWhereView ORDER BY $sqlBibNumP, p.par_nom, p.par_prenom"; $tabParticipants = $objDatabase->fxGetResults($sqlParticipants); } ob_start(); ?>
"; if ($tabEpreuve['epr_type_' . $strLangue] != '') echo $tabEpreuve['epr_type_' . $strLangue]; echo " (" . $tabEpreuve['epr_id'] . ")"; ?>
fxGetVar($sqlOrder)); // ===================== // SÉCURITÉ / FALLBACK // Si aucun ordre valide, on garde un ordre stable. // ===================== if ($orderBy == '') { $orderBy = "p.par_nom, p.par_prenom"; } // ===================== // PARTICIPANTS À ASSIGNER (solo et équipe) // - jointure c.* requise pour les tris par nom d'équipe (pec_nom_equipe) // - on ne prend que ceux sans no_bib // - on exclut rol_id 3 et 4 comme dans l'ancien code // ===================== $sql = " SELECT p.*, p.pec_id, c.pec_id_original, c.pec_nom_equipe, c.no_equipe, ie.epr_bib_team_mode 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 LEFT JOIN inscriptions_epreuves ie ON ie.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) ORDER BY $orderBy "; return $objDatabase->fxGetResults($sql); } function fxGetRangesForBatchAssign($epr_id, $ranges) { global $objDatabase; // ===================== // VALIDATION // ===================== $epr_id = intval($epr_id); if ($epr_id <= 0 || empty($ranges) || !is_array($ranges)) { return []; } // Nettoyage des IDs (sécurité) $ids = array_map('intval', $ranges); $ids = array_filter($ids); if (empty($ids)) { return []; } // ===================== // QUERY LÉGÈRE // ===================== $strIds = implode(',', $ids); $sql = " SELECT epr_bib_id, epr_bib_start, epr_bib_finish FROM inscriptions_epreuves_bib WHERE epr_id = $epr_id AND epr_bib_id IN ($strIds) AND epr_bib_start IS NOT NULL AND epr_bib_finish IS NOT NULL ORDER BY epr_bib_start "; $rows = $objDatabase->fxGetResults($sql); // ===================== // NORMALISATION // ===================== $out = []; if (is_array($rows)) { foreach ($rows as $r) { $start = (int)$r['epr_bib_start']; $end = (int)$r['epr_bib_finish']; // sécurité if ($start > 0 && $end >= $start) { $out[] = [ 'id' => (int)$r['epr_bib_id'], 'start' => $start, 'end' => $end ]; } } } return $out; } function fxGetNextAvailableBib($epr_id, $tabRanges) { global $objDatabase; $epr_id = intval($epr_id); $sqlBibNum = fxBibSqlNoBibUnsigned('no_bib'); if ($epr_id <= 0 || empty($tabRanges)) { return null; } // ===================== // PARCOURIR LES RANGES // ===================== foreach ($tabRanges as $range) { $start = (int)$range['start']; $end = (int)$range['end']; if ($start <= 0 || $end < $start) { continue; } // ===================== // CHERCHER UN BIB LIBRE DANS CE RANGE // ===================== for ($i = $start; $i <= $end; $i++) { $sql = " SELECT COUNT(*) FROM resultats_participants WHERE epr_id = $epr_id AND $sqlBibNum = $i "; $exists = (int)$objDatabase->fxGetVar($sql); // 👉 trouvé un BIB libre if ($exists === 0) { return $i; } } } // 👉 aucun BIB disponible return null; } function fxLoadUsedBibsForBatch($epr_id) { global $objDatabase; $usedBib = []; $sql = " SELECT no_bib FROM resultats_participants WHERE epr_id = " . intval($epr_id) . " AND no_bib IS NOT NULL AND no_bib != '' AND no_bib > 0 "; $rows = $objDatabase->fxGetResults($sql); if (is_array($rows)) { foreach ($rows as $r) { $usedBib[(int)$r['no_bib']] = true; } } return $usedBib; } /** * Cherche le prochain dossard libre dans les séquences sélectionnées. * * Règle anti-doublon (mode execute / GO) : * - solo ou équipe « dossards individuels » : un numéro = une personne (COUNT participants) * - équipe « 1 équipe = 1 dossard » : un numéro = une équipe (COUNT DISTINCT pec_id) * → plusieurs coéquipiers peuvent partager le même no_bib * * @param int $teamMode epr_bib_team_mode (1 = individuel, 3 = 1 équipe = 1 dossard) */ function fxFindNextBatchBib($epr_id, $tabRanges, $mode, &$usedBib, $teamMode = 1) { $epr_id = intval($epr_id); $teamMode = (int)$teamMode; foreach ($tabRanges as $range) { $start = (int)$range['start']; $end = (int)$range['end']; for ($i = $start; $i <= $end; $i++) { if (!isset($usedBib[$i])) { // MSIN-4433 — simulation : réserve en mémoire ; execute : réservation après UPDATE réussi. if ($mode === 'simulation') { $usedBib[$i] = true; } return $i; } } } return null; } /** * MSIN-4433 — Vérifie en BD qu'un numéro est encore libre (assignation manuelle entre-temps). */ function fxBibIsNumberFreeInDb($epr_id, $intBib, $teamMode = 1) { global $objDatabase; $epr_id = (int)$epr_id; $intBib = (int)$intBib; $teamMode = (int)$teamMode; $sqlBibNum = fxBibSqlNoBibUnsigned('no_bib'); if ($epr_id <= 0 || $intBib <= 0) { return false; } if ($teamMode === 3) { $sqlCheck = " SELECT COUNT(DISTINCT pec_id) FROM resultats_participants WHERE epr_id = $epr_id AND $sqlBibNum = $intBib AND pec_id > 0 "; return (int)$objDatabase->fxGetVar($sqlCheck) === 0; } $sqlCheck = " SELECT COUNT(*) FROM resultats_participants WHERE epr_id = $epr_id AND $sqlBibNum = $intBib "; return (int)$objDatabase->fxGetVar($sqlCheck) === 0; } /** * MSIN-4433 — Prochain dossard libre pour un participant (1 UPDATE si execute). * Relecture BD avant écriture : cohérence si changement manuel pendant le batch. * * @return int|null Numéro attribué, ou null si épuisé / participant déjà servi. */ function fxTryAssignNextBibForParticipant($epr_id, $par_id, $tabRanges, $mode, &$usedBib, $teamMode = 1) { $epr_id = (int)$epr_id; $par_id = (int)$par_id; $teamMode = (int)$teamMode; $intMaxAttempts = 50000; for ($intAttempt = 0; $intAttempt < $intMaxAttempts; $intAttempt++) { $candidate = fxFindNextBatchBib($epr_id, $tabRanges, $mode, $usedBib, $teamMode); if ($candidate === null) { return null; } if ($mode === 'execute') { if (!fxBibIsNumberFreeInDb($epr_id, $candidate, $teamMode)) { $usedBib[$candidate] = true; continue; } $intAffected = fxApplyBatchParticipantBib($epr_id, $par_id, $candidate); if ($intAffected <= 0) { return null; } $usedBib[$candidate] = true; return (int)$candidate; } return (int)$candidate; } return null; } /** * Écrit le no_bib d'un participant (batch GO). * Note : en mode « 1 équipe = 1 dossard », plusieurs lignes peuvent légitimement * recevoir le même no_bib — ce n'est pas un doublon erroné. */ function fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib) { global $objDatabase; $sqlUpdate = " UPDATE resultats_participants SET no_bib = " . intval($foundBib) . ", par_date_bib = IFNULL(par_date_bib, NOW()) WHERE par_id = " . intval($par_id) . " AND is_cancelled = 0 AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0) "; $objDatabase->fxQuery($sqlUpdate); $intAffected = (int)$objDatabase->affected_rows; if ($intAffected > 0 && function_exists('fxEvtErreurResoudre')) { fxEvtErreurResoudre('bib_auto_miss', (int)$epr_id, (int)$par_id); } return $intAffected; } function fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, &$updatedTeams) { global $objDatabase; if ($teamKey <= 0 || $teamNumber <= 0 || isset($updatedTeams[$teamKey])) { return; } $sqlTeam = " UPDATE resultats_epreuves_commandees SET no_equipe = " . intval($teamNumber) . " WHERE pec_id_original = " . intval($teamKey) . " AND epr_id = " . intval($epr_id) . " "; $objDatabase->fxQuery($sqlTeam); $updatedTeams[$teamKey] = true; } function fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber) { return [ 'rol_id' => $p['rol_id'], 'par_id' => (int)$p['par_id'], 'par_prenom' => $p['par_prenom'], 'par_nom' => $p['par_nom'], 'no_bib' => $foundBib, 'no_equipe' => $teamNumber, 'pec_nom_equipe' => $p['pec_nom_equipe'] ?? '', ]; } function fxGetBatchTeamKey($p) { return (int)($p['pec_id_original'] ?? $p['pec_id'] ?? 0); } /** * MSIN-4433 — Mode équipe 3 : dossard déjà posé sur un coéquipier (batch par paquets). */ function fxGetExistingTeamBibInDb($epr_id, $teamKey) { global $objDatabase; $epr_id = (int)$epr_id; $teamKey = (int)$teamKey; $sqlBibNum = fxBibSqlNoBibUnsigned('no_bib'); if ($epr_id <= 0 || $teamKey <= 0) { return null; } $sql = " SELECT $sqlBibNum FROM resultats_participants WHERE epr_id = $epr_id AND pec_id = $teamKey AND is_cancelled = 0 AND $sqlBibNum > 0 LIMIT 1 "; $bib = (int)$objDatabase->fxGetVar($sql); return $bib > 0 ? $bib : null; } function fxCountBatchAssignUnits($epr_id, $participants = null) { global $objDatabase; $epr_id = intval($epr_id); if ($epr_id <= 0) { return 0; } $sqlEpreuve = " SELECT epr_equipe, epr_bib_team_mode FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1 "; $tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve); $countParticipants = function ($rows) { return is_array($rows) ? count($rows) : 0; }; if (!$tabEpreuve || (int)$tabEpreuve['epr_equipe'] !== 1) { if (is_array($participants)) { return $countParticipants($participants); } return (int)$objDatabase->fxGetVar(" SELECT COUNT(*) FROM resultats_participants WHERE epr_id = $epr_id AND is_cancelled = 0 AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0) AND rol_id NOT IN (3, 4) "); } $teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1); if ($teamMode <= 0) { $teamMode = 1; } if ($teamMode !== 3) { if (is_array($participants)) { return $countParticipants($participants); } return (int)$objDatabase->fxGetVar(" SELECT COUNT(*) FROM resultats_participants WHERE epr_id = $epr_id AND is_cancelled = 0 AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0) AND rol_id NOT IN (3, 4) "); } if (is_array($participants)) { $teams = []; foreach ($participants as $p) { $teamKey = fxGetBatchTeamKey($p); if ($teamKey > 0) { $teams[$teamKey] = true; } } return count($teams); } return (int)$objDatabase->fxGetVar(" SELECT COUNT(DISTINCT p.pec_id) FROM resultats_participants p 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 "); } function fxProcessBatchAssignmentsSolo($epr_id, $participants, $tabRanges, $mode = 'simulation') { $assignments = []; // MSIN-4433 — état réel rechargé à chaque paquet (execute) ou simulation. $usedBib = fxLoadUsedBibsForBatch($epr_id); foreach ($participants as $p) { $foundBib = fxTryAssignNextBibForParticipant( $epr_id, (int)$p['par_id'], $tabRanges, $mode, $usedBib, 1 ); if ($foundBib === null) { break; } $assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, 0); } return $assignments; } function fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mode, $teamMode) { $assignments = []; $teamMap = []; $updatedTeams = []; $teamBibMap = []; $nextTeamNumber = 1; $usedBib = fxLoadUsedBibsForBatch($epr_id); foreach ($participants as $p) { $par_id = (int)$p['par_id']; $teamKey = fxGetBatchTeamKey($p); $teamNumber = 0; $foundBib = null; if ($teamMode === 3 && $teamKey > 0) { if (isset($teamBibMap[$teamKey])) { $foundBib = $teamBibMap[$teamKey]; } else { $foundBib = fxGetExistingTeamBibInDb($epr_id, $teamKey); if ($foundBib !== null) { $teamBibMap[$teamKey] = $foundBib; } } } if ($teamMode === 3 && $teamKey > 0 && $foundBib !== null) { $teamNumber = $foundBib; if ($mode === 'execute') { $intAffected = fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib); if ($intAffected <= 0) { continue; } fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams); } } else { if ($teamMode !== 3 && $teamKey > 0) { if (!isset($teamMap[$teamKey])) { $teamMap[$teamKey] = $nextTeamNumber; $nextTeamNumber++; } $teamNumber = $teamMap[$teamKey]; } $foundBib = fxTryAssignNextBibForParticipant( $epr_id, $par_id, $tabRanges, $mode, $usedBib, $teamMode ); if ($foundBib === null) { break; } if ($teamMode === 3 && $teamKey > 0) { $teamBibMap[$teamKey] = $foundBib; $teamNumber = $foundBib; } if ($mode === 'execute') { fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams); } } $assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber); } return $assignments; } function fxProcessBatchAssignments($epr_id, $participants, $tabRanges, $mode = 'simulation') { global $objDatabase; if (empty($participants) || empty($tabRanges)) { return []; } $epr_id = intval($epr_id); $sqlEpreuve = " SELECT epr_equipe, epr_bib_team_mode FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1 "; $tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve); // Épreuves solo : logique simple, inchangée (1 personne = 1 dossard) if (!$tabEpreuve || (int)$tabEpreuve['epr_equipe'] !== 1) { return fxProcessBatchAssignmentsSolo($epr_id, $participants, $tabRanges, $mode); } // Épreuves équipe uniquement — voir fxProcessBatchAssignmentsEquipe() $teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1); if ($teamMode <= 0) { $teamMode = 1; } return fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mode, $teamMode); } /** MSIN-4433 — Clé session pour accumuler les lignes assignées entre paquets AJAX. */ function fxBibBatchExecSessionKey($epr_id) { return 'bib_batch_exec_' . (int)$epr_id; } /** * MSIN-4433 — HTML résultat GO batch (batch_apply et dernier paquet). */ function fxBibBuildBatchApplyHtml($epr_id, array $exec, $intTotalInitial, $strLangue) { $assigned = count($exec); $total = max($assigned, (int)$intTotalInitial); $remaining = max(0, $total - $assigned); $status = 'success'; if ($assigned === 0) { $status = 'error'; } elseif ($assigned < $total) { $status = 'partial'; } if ($assigned === 0) { $info = fxBibMsg('bib_v4_ajax_assign_none'); } elseif ($assigned >= $total) { $info = fxBibMsg('bib_v4_ajax_assign_full', $assigned); } else { $info = fxBibMsg('bib_v4_ajax_assign_partial', $assigned, $remaining); } return renderBibView( $epr_id, 0, $strLangue, 'execute', $exec, fxBibTexte('bib_v4_ajax_title_assign'), $info, $status ); } function fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id = 0) { $nbParticipants = fxCountBatchAssignUnits($epr_id, $participants); $nbDispo = 0; if (!empty($tabRangesInfos)) { foreach ($tabRangesInfos as $r) { $total = (int)($r['nb_total_range'] ?? 0); $used = (int)($r['nb_utilises'] ?? 0); $nbDispo += max(0, $total - $used); } } $nbAssignable = min($nbParticipants, $nbDispo); $nbManque = max(0, $nbParticipants - $nbDispo); return [ 'nb_dispo' => $nbDispo, 'nb_participants' => $nbParticipants, 'nb_assignable' => $nbAssignable, 'nb_manque' => $nbManque ]; } function fxGetParticipantsForBatchReset($epr_id, $ranges) { global $objDatabase; $epr_id = intval($epr_id); if ($epr_id <= 0 || empty($ranges) || !is_array($ranges)) { return []; } $ids = array_map('intval', $ranges); $ids = array_filter($ids); if (empty($ids)) { return []; } $tabRanges = fxGetRangesForBatchAssign($epr_id, $ids); if (empty($tabRanges)) { return []; } $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); $where = []; foreach ($tabRanges as $r) { $start = (int)$r['start']; $end = (int)$r['end']; $where[] = "($sqlBibNumP BETWEEN $start AND $end)"; } if (empty($where)) { return []; } $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 AND ( " . implode(' OR ', $where) . " ) ORDER BY $sqlBibNumP "; return $objDatabase->fxGetResults($sql); } function fxResolveTeamBib( $p, &$teamBibMap, $epr_id ) { global $objDatabase; $teamKey = (int)($p['pec_id'] ?? 0); if ($teamKey <= 0) { return null; } // ===================== // MÉMOIRE // ===================== if (isset($teamBibMap[$teamKey])) { return $teamBibMap[$teamKey]; } // ===================== // DB EXISTANTE // ===================== $sql = " SELECT no_equipe FROM resultats_epreuves_commandees WHERE pec_id_original = $teamKey AND epr_id = " . intval($epr_id) . " LIMIT 1 "; $existingBib = (int)$objDatabase->fxGetVar($sql); if ($existingBib > 0) { $teamBibMap[$teamKey] = $existingBib; return $existingBib; } return null; }