10639 lines
446 KiB
PHP
10639 lines
446 KiB
PHP
<?php
|
||
require_once(__DIR__ . '/inc_fx_bib_production.php');
|
||
|
||
/**
|
||
* Created by PhpStorm.
|
||
* User: AlexL
|
||
* Date: 19/05/2015
|
||
* Time: 9:29 AM
|
||
*/
|
||
|
||
// MSIN-1152 : fonction qui affiche un formulaire de recherche.
|
||
/*
|
||
* param $str_code : le code (URL) du "action" du formulaire
|
||
* param $int_promoteur_id : le no. de l'evenement pour lequel l'usager est promoteur
|
||
* param $str_code : un code pour definir les champs de recherche selon le contexte
|
||
* */
|
||
function fxShowRecherche($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;
|
||
}
|
||
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 .= '
|
||
<form action="' . $vDomaine . '/' . $str_code . '" id="frm_search" name="frm_search" method="get">
|
||
<input type="hidden" name="promoteur_eve_id" value="' . urlencode(base64_encode($int_promoteur_id)) . '">
|
||
<div class="form-group row">
|
||
<label for="rech_prenom" class="control-label col-sm-3 text-sm-right">' . afficheTexte($strPrenom, 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_prenom" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_nom" class="control-label col-sm-3 text-sm-right">' . afficheTexte($strNom, 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_nom" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_no_commande" class="control-label col-sm-3 text-sm-right">' . afficheTexte('rech_no_commande', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_no_commande" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_nom_equipe" class="control-label col-sm-3 text-sm-right">' . afficheTexte($strEquipe, 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_nom_equipe" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="chk_bib" class="form-label col-sm-3 text-sm-right">' . afficheTexte('chk_bib', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control0" type="checkbox" name="chk_bib" value="1">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="chk_cancelled" class="form-label col-sm-3 text-sm-right">' . afficheTexte('chk_cancelled', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control0" type="checkbox" name="chk_cancelled" value="1">
|
||
</div>
|
||
</div>
|
||
';
|
||
|
||
if ($blnDon) {
|
||
$strRechercheForm .= '
|
||
<div class="form-group row">
|
||
<label for="rech_prenom_participant" class="control-label col-sm-3 text-sm-right">' . afficheTexte('rech_prenom_participant', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_prenom_participant" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_nom_participant" class="control-label col-sm-3 text-sm-right">' . afficheTexte('rech_nom_participant', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_nom_participant" value="">
|
||
</div>
|
||
</div>
|
||
';
|
||
}
|
||
|
||
if (!$blnDon) { // un champ pour chercher par nom d'equipe
|
||
$sqlEpreuves = "SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = " . intval($int_promoteur_id) . " AND ((SELECT COUNT(*) from resultats_participants p where p.epr_id = e.epr_id > 0))";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
|
||
$strRechercheForm .= '
|
||
<div class="form-group row">
|
||
<label for="sel_rech_epreuve" class="control-label col-sm-3 text-sm-right">' . afficheTexte('sel_rech_epreuve', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<select class="form-control rounded-0" id="sel_rech_epreuve" name="sel_rech_epreuve">
|
||
<option value="0" data-comment="Pour champ recherche vide">--</option>
|
||
';
|
||
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++) {
|
||
$strEpreuve = '';
|
||
|
||
if (trim($tabEpreuves[$i]['epr_categorie_' . $strLangue]) != '') {
|
||
$strEpreuve .= $tabEpreuves[$i]['epr_categorie_' . $strLangue] . " - ";
|
||
}
|
||
|
||
$strEpreuve .= $tabEpreuves[$i]['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuves[$i]['epr_nom_' . $strLangue]) != '') {
|
||
$strEpreuve .= " - " . $tabEpreuves[$i]['epr_nom_' . $strLangue];
|
||
}
|
||
|
||
if (isset($_GET['sel_rech_epreuve']) && $tabEpreuves[$i]['epr_id'] == $_GET['sel_rech_epreuve']) {
|
||
$strSelected = ' selected';
|
||
}
|
||
|
||
$strRechercheForm .= '<option' . $strSelected . ' value="' . urlencode(base64_encode($tabEpreuves[$i]['epr_id'])) . '">' . $strEpreuve . '</option>';
|
||
}
|
||
|
||
$strRechercheForm .= '
|
||
</select>
|
||
</div>
|
||
</div>
|
||
';
|
||
}
|
||
|
||
$strRechercheForm .= '
|
||
<div class="form-group row">
|
||
<div class="offset-sm-3 col-sm-9 col-lg-7">
|
||
<button class="btn btn-primary rounded-0" type="submit" id="btn_recherche" name="btn_recherche">' . afficheTexte('txt_recherche', 0) . '</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
';
|
||
|
||
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 .= '
|
||
<div class="card-header mb-3">
|
||
<h2>' . afficheTexte('promoteur_liste_inscrits', 0) . '</h2>
|
||
</div>
|
||
<div class="table-responsive-sm">
|
||
<table class="table">
|
||
<thead>
|
||
<tr>
|
||
';
|
||
|
||
foreach ($arrColonnes as $intIndex => $arrValues) {
|
||
$strRechercheResultats .= '
|
||
<th class="text-' . fxUnescape($arrValues['align']) . '">' . fxUnescape($arrValues['label_' . $strLangue]) . '</th>
|
||
';
|
||
}
|
||
|
||
$strRechercheResultats .= '
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
';
|
||
|
||
$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 .= '
|
||
<tr class="' . $strClasse . '">
|
||
';
|
||
|
||
$strRechercheResultats .= fxShowColumnPromoteur($arrColonnes, $tabInscriptionsParPage, $j, $strLangue, $tabInscriptionsParPage[$j]['pec_equipe'],$abonnement);
|
||
|
||
$strRechercheResultats .= '
|
||
</tr>
|
||
';
|
||
}
|
||
|
||
$intNbPagesTotal = ceil($intNbInscriptions / $intNbItemsParPage); // calculer le nb de pages
|
||
$intNbItemsAffiches = $intEnd - ($intStart - 1);
|
||
|
||
if ($strLangue == 'fr') {
|
||
$strStatut = $intNbItemsAffiches . ' de ' . $intNbInscriptions . '<br>page ' . $intPage . ' de ' . $intNbPagesTotal;
|
||
} else {
|
||
$strStatut = $intNbItemsAffiches . ' of ' . $intNbInscriptions . '<br>page ' . $intPage . ' of ' . $intNbPagesTotal;
|
||
}
|
||
|
||
$strRechercheResultats .= '
|
||
</tbody>
|
||
<tfoot>
|
||
<tr>
|
||
<th class="text-center" colspan="' . count($arrColonnes) . '">' . $strStatut . '</th>
|
||
</tr>
|
||
</tfoot>
|
||
</table>
|
||
</div>
|
||
';
|
||
|
||
// 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 = '
|
||
<div class="alert alert-danger" role="alert">
|
||
' . afficheTexte('txt_recherche_no_result', 0) . '
|
||
</div>
|
||
';
|
||
}
|
||
|
||
$strDisplay = (!isset($_GET['pg']) && !isset($_GET['btn_recherche'])) ? '' : ' show';
|
||
$strIcon = "'" . $vDomaine . "/images/search-icon.png'";
|
||
|
||
$strRetour .= '
|
||
<div class="card-header">
|
||
<h2>' . afficheTexte('txt_recherche', 0) . '</h2>
|
||
</div>
|
||
<div class="card-body">
|
||
<a class="button-promoteur" style="background: url(' . $strIcon . ') no-repeat center" data-toggle="collapse" href="#collapseSearch" role="button" aria-expanded="false" aria-controls="collapseSearch">
|
||
<span class="d-inline-block h-100 w-100" data-toggle="tooltip" title="' . afficheTexte('promoteur_div_tooltip', 0) . '"></span>
|
||
</a>
|
||
</div>
|
||
<div class="animate__animated animate__fadeIn collapse' . $strDisplay . '" id="collapseSearch">
|
||
<div class="card-body text-left">
|
||
' . $strRechercheForm . '
|
||
</div>
|
||
' . $strRechercheResultats . '
|
||
' . $strRecherchePagination . '
|
||
</div>
|
||
';
|
||
|
||
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 .= '
|
||
<form action="' . $vDomaine . '/' . $str_code . '" id="frm_search" name="frm_search" method="get">
|
||
<input type="hidden" name="promoteur_eve_id" value="' . urlencode(base64_encode($int_promoteur_id)) . '">
|
||
<div class="form-group row">
|
||
<label for="rech_prenom" class="control-label col-sm-3 text-sm-right">' . afficheTexte($strPrenom, 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_prenom" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_nom" class="control-label col-sm-3 text-sm-right">' . afficheTexte($strNom, 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_nom" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_no_commande" class="control-label col-sm-3 text-sm-right">' . afficheTexte('rech_no_commande', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_no_commande" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_nom_equipe" class="control-label col-sm-3 text-sm-right">' . afficheTexte($strEquipe, 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_nom_equipe" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="chk_bib" class="form-label col-sm-3 text-sm-right">' . afficheTexte('chk_bib', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control0" type="checkbox" name="chk_bib" value="1">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="chk_cancelled" class="form-label col-sm-3 text-sm-right">' . afficheTexte('chk_cancelled', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control0" type="checkbox" name="chk_cancelled" value="1">
|
||
</div>
|
||
</div>
|
||
';
|
||
|
||
if ($blnDon) {
|
||
$strRechercheForm .= '
|
||
<div class="form-group row">
|
||
<label for="rech_prenom_participant" class="control-label col-sm-3 text-sm-right">' . afficheTexte('rech_prenom_participant', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_prenom_participant" value="">
|
||
</div>
|
||
</div>
|
||
<div class="form-group row">
|
||
<label for="rech_nom_participant" class="control-label col-sm-3 text-sm-right">' . afficheTexte('rech_nom_participant', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<input class="form-control rounded-0" type="text" name="rech_nom_participant" value="">
|
||
</div>
|
||
</div>
|
||
';
|
||
}
|
||
|
||
if (!$blnDon) { // un champ pour chercher par nom d'equipe
|
||
$sqlEpreuves = "SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = " . intval($int_promoteur_id) . " AND ((SELECT COUNT(*) from resultats_participants p where p.epr_id = e.epr_id > 0))";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
|
||
$strRechercheForm .= '
|
||
<div class="form-group row">
|
||
<label for="sel_rech_epreuve" class="control-label col-sm-3 text-sm-right">' . afficheTexte('sel_rech_epreuve', 0) . ' :</label>
|
||
<div class="col-sm-9 col-lg-7">
|
||
<select class="form-control rounded-0" id="sel_rech_epreuve" name="sel_rech_epreuve">
|
||
<option value="0" data-comment="Pour champ recherche vide">--</option>
|
||
';
|
||
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++) {
|
||
$strEpreuve = '';
|
||
|
||
if (trim($tabEpreuves[$i]['epr_categorie_' . $strLangue]) != '') {
|
||
$strEpreuve .= $tabEpreuves[$i]['epr_categorie_' . $strLangue] . " - ";
|
||
}
|
||
|
||
$strEpreuve .= $tabEpreuves[$i]['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuves[$i]['epr_nom_' . $strLangue]) != '') {
|
||
$strEpreuve .= " - " . $tabEpreuves[$i]['epr_nom_' . $strLangue];
|
||
}
|
||
|
||
if (isset($_GET['sel_rech_epreuve']) && $tabEpreuves[$i]['epr_id'] == $_GET['sel_rech_epreuve']) {
|
||
$strSelected = ' selected';
|
||
}
|
||
|
||
$strRechercheForm .= '<option' . $strSelected . ' value="' . urlencode(base64_encode($tabEpreuves[$i]['epr_id'])) . '">' . $strEpreuve . '</option>';
|
||
}
|
||
|
||
$strRechercheForm .= '
|
||
</select>
|
||
</div>
|
||
</div>
|
||
';
|
||
}
|
||
|
||
$strRechercheForm .= '
|
||
<div class="form-group row">
|
||
<div class="offset-sm-3 col-sm-9 col-lg-7">
|
||
<button class="btn btn-primary rounded-0" type="submit" id="btn_recherche" name="btn_recherche">' . afficheTexte('txt_recherche', 0) . '</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
';
|
||
|
||
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 .= '
|
||
<div class="card-header mb-3">
|
||
<h2>' . afficheTexte('promoteur_liste_inscrits', 0) . '</h2>
|
||
</div>
|
||
<div class="table-responsive-sm">
|
||
<table class="table">
|
||
<thead>
|
||
<tr>
|
||
';
|
||
|
||
foreach ($arrColonnes as $intIndex => $arrValues) {
|
||
$strRechercheResultats .= '
|
||
<th class="text-' . fxUnescape($arrValues['align']) . '">' . fxUnescape($arrValues['label_' . $strLangue]) . '</th>
|
||
';
|
||
}
|
||
|
||
$strRechercheResultats .= '
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
';
|
||
|
||
$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 .= '
|
||
<tr class="' . $strClasse . '">
|
||
';
|
||
|
||
$strRechercheResultats .= fxShowColumnPromoteur($arrColonnes, $tabInscriptionsParPage, $j, $strLangue, $tabInscriptionsParPage[$j]['pec_equipe'],$abonnement);
|
||
|
||
$strRechercheResultats .= '
|
||
</tr>
|
||
';
|
||
}
|
||
|
||
$intNbPagesTotal = ceil($intNbInscriptions / $intNbItemsParPage); // calculer le nb de pages
|
||
$intNbItemsAffiches = $intEnd - ($intStart - 1);
|
||
|
||
if ($strLangue == 'fr') {
|
||
$strStatut = $intNbItemsAffiches . ' de ' . $intNbInscriptions . '<br>page ' . $intPage . ' de ' . $intNbPagesTotal;
|
||
} else {
|
||
$strStatut = $intNbItemsAffiches . ' of ' . $intNbInscriptions . '<br>page ' . $intPage . ' of ' . $intNbPagesTotal;
|
||
}
|
||
|
||
$strRechercheResultats .= '
|
||
</tbody>
|
||
<tfoot>
|
||
<tr>
|
||
<th class="text-center" colspan="' . count($arrColonnes) . '">' . $strStatut . '</th>
|
||
</tr>
|
||
</tfoot>
|
||
</table>
|
||
</div>
|
||
';
|
||
|
||
// 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 = '
|
||
<div class="alert alert-danger" role="alert">
|
||
' . afficheTexte('txt_recherche_no_result', 0) . '
|
||
</div>
|
||
';
|
||
}
|
||
|
||
$strDisplay = (!isset($_GET['pg']) && !isset($_GET['btn_recherche'])) ? '' : ' show';
|
||
$strIcon = "'" . $vDomaine . "/images/search-icon.png'";
|
||
|
||
$strRetour .= '
|
||
<div class="card-header">
|
||
<h2>' . afficheTexte('txt_recherche', 0) . '</h2>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="card-body text-left">
|
||
' . $strRechercheForm . '
|
||
</div>
|
||
' . $strRechercheResultats . '
|
||
' . $strRecherchePagination . '
|
||
</div>
|
||
';
|
||
|
||
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);
|
||
?>
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_qte_mgr')?></h2>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<a class="button-promoteur" style="background: url('<?php echo $vDomaine; ?>/images/plus-minus.png') no-repeat center" data-toggle="collapse" href="#collapseQuantites" role="button" aria-expanded="false" aria-controls="collapseQuantites">
|
||
<span class="d-inline-block h-100 w-100" data-toggle="tooltip" title="<?php afficheTexte('promoteur_div_tooltip')?>"></span>
|
||
</a>
|
||
</div>
|
||
<div class="animate__animated animate__fadeIn collapse" id="collapseQuantites">
|
||
<div class="table-responsive-sm">
|
||
<table class="table" id="table_qtes">
|
||
<thead>
|
||
<tr>
|
||
<th><?php afficheTexte('promoteur_qte_epr_id')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_type')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_original_qte')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_ajustement')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_qte_total')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_qte_ordered')?></th>
|
||
<th style="width:100px"><?php afficheTexte('promoteur_qte_epr_qte')?></th>
|
||
<th style="width:10px"><?php afficheTexte('promoteur_qte_checkin')?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
$intTotalOriginal = $intTotalAvailable = $intTotalBooked = $intTotalCurrent = $intTotalAjustement = 0;
|
||
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++){
|
||
$strClass = ($i & 1) ? '' : 'table-secondary';
|
||
$tabEpreuve = fxGetEpreuve($tabEpreuves[$i]['epr_id']);
|
||
$arrQuantites = fxGetQuantites($tabEpreuve['epr_id']);
|
||
$QCheckin = fxGetCheckinqte($tabEpreuve['epr_id']);
|
||
$intTotalOriginal += $arrQuantites['qte_origine'];
|
||
$intTotalAvailable += $arrQuantites['qte_restante'];
|
||
$intTotalBooked += $arrQuantites['qte_inscrits'];
|
||
$intTotalCurrent += $arrQuantites['qte_courante'];
|
||
$intTotalAjustement += $arrQuantites['qte_ajustement'];
|
||
$intTotalCheckin+=$QCheckin;
|
||
?>
|
||
<tr class="<?php echo $strClass; ?>">
|
||
<td><?php echo $tabEpreuve['epr_id']; ?></td>
|
||
<td><?php
|
||
if (trim($tabEpreuve['epr_categorie_' . $strLangue]) != '') {
|
||
echo $tabEpreuve['epr_categorie_' . $strLangue] . "<br>";
|
||
}
|
||
|
||
echo $tabEpreuve['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') {
|
||
echo "<br>" . $tabEpreuve['epr_nom_' . $strLangue];
|
||
}
|
||
?>
|
||
</td>
|
||
<td id="qte_origine_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_origine']; ?>
|
||
</td>
|
||
<td id="qte_ajustement_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_ajustement']; ?>
|
||
</td>
|
||
<td id="qte_courante_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_courante']; ?>
|
||
</td>
|
||
<td id="qte_inscrits_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_inscrits']; ?>
|
||
</td>
|
||
<td>
|
||
<?php fxShowAjouterQuantite($tabEpreuve['epr_id'], $arrQuantites['qte_restante'], $strLangue); ?>
|
||
</td>
|
||
<td id="qte_checkin_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $QCheckin; ?>
|
||
</td>
|
||
</tr>
|
||
<?php
|
||
}
|
||
?>
|
||
</tbody>
|
||
<tfoot>
|
||
<tr>
|
||
<th> </th>
|
||
<th> </th>
|
||
<th id="qte_origine_total">
|
||
<?php echo $intTotalOriginal; ?>
|
||
</th>
|
||
<th id="qte_ajustement_total">
|
||
<?php echo $intTotalAjustement; ?>
|
||
</th>
|
||
<th id="qte_courante_total">
|
||
<?php echo $intTotalCurrent; ?>
|
||
</th>
|
||
<th id="qte_inscrits_total">
|
||
<?php echo $intTotalBooked; ?></th>
|
||
<th id="qte_restante_total">
|
||
<?php echo $intTotalAvailable; ?></th>
|
||
<th id="qte_checkin_total">
|
||
<?php echo $intTotalCheckin; ?></th>
|
||
</tr>
|
||
</tfoot>
|
||
<?php
|
||
?>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
function fxShowQuantitesv2($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);
|
||
?>
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_qte_mgr')?></h2>
|
||
</div>
|
||
|
||
<div >
|
||
<div class="table-responsive-sm">
|
||
<table class="table" id="table_qtes">
|
||
<thead>
|
||
<tr>
|
||
<th><?php afficheTexte('promoteur_qte_epr_id')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_type')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_original_qte')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_ajustement')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_qte_total')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_qte_ordered')?></th>
|
||
<th style="width:100px"><?php afficheTexte('promoteur_qte_epr_qte')?></th>
|
||
<th style="width:10px"><?php afficheTexte('promoteur_qte_checkin')?></th>
|
||
<th style="width:10px"><?php afficheTexte('promoteur_lattente_actif_colonne')?></th>
|
||
<th style="width:10px"><?php afficheTexte('promoteur_lattente_nb')?></th>
|
||
<th style="width:10px"><?php afficheTexte('promoteur_lattente_nbtotal')?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
$intTotalOriginal =$intTotalnbSurListea = $intTotalnbSurListe =$intTotalAvailable = $intTotalBooked = $intTotalCurrent = $intTotalAjustement = 0;
|
||
$intTotalCheckin=0;
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++){
|
||
$strClass = ($i & 1) ? '' : 'table-secondary';
|
||
$tabEpreuve = fxGetEpreuve($tabEpreuves[$i]['epr_id']);
|
||
$arrQuantites = fxGetQuantites($tabEpreuve['epr_id']);
|
||
$QCheckin = fxGetCheckinqte($tabEpreuve['epr_id']);
|
||
$intTotalOriginal += $arrQuantites['qte_origine'];
|
||
$intTotalAvailable += $arrQuantites['qte_restante'];
|
||
$intTotalBooked += $arrQuantites['qte_inscrits'];
|
||
$intTotalCurrent += $arrQuantites['qte_courante'];
|
||
$intTotalAjustement += $arrQuantites['qte_ajustement'];
|
||
$intTotalCheckin+=$QCheckin;
|
||
?>
|
||
<tr class="<?php echo $strClass; ?>">
|
||
<td><?php echo $tabEpreuve['epr_id']; ?></td>
|
||
<td><?php
|
||
if (trim($tabEpreuve['epr_categorie_' . $strLangue]) != '') {
|
||
echo $tabEpreuve['epr_categorie_' . $strLangue] . "<br>";
|
||
}
|
||
|
||
echo $tabEpreuve['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') {
|
||
echo "<br>" . $tabEpreuve['epr_nom_' . $strLangue];
|
||
}
|
||
?>
|
||
</td>
|
||
<td id="qte_origine_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_origine']; ?>
|
||
</td>
|
||
<td id="qte_ajustement_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_ajustement']; ?>
|
||
</td>
|
||
<td id="qte_courante_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_courante']; ?>
|
||
</td>
|
||
<td id="qte_inscrits_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $arrQuantites['qte_inscrits']; ?>
|
||
</td>
|
||
<td>
|
||
<?php fxShowAjouterQuantite($tabEpreuve['epr_id'], $arrQuantites['qte_restante'], $strLangue); ?>
|
||
</td>
|
||
<td id="qte_checkin_<?php echo $tabEpreuve['epr_id']; ?>">
|
||
<?php echo $QCheckin; ?>
|
||
</td>
|
||
<td >
|
||
<?php fx_liste_attente_btactiver($int_eve_id,$tabEpreuve['epr_id'])?><br>
|
||
</td>
|
||
<td >
|
||
<?php
|
||
$intTotalnbSurListea+=fx_liste_attente_nombre_surliste($tabEpreuve['epr_id'],1);
|
||
echo ($nbSurListe = fx_liste_attente_nombre_surliste($tabEpreuve['epr_id'],1)) > 0 ? $nbSurListe : '';?>
|
||
|
||
|
||
</td>
|
||
<td >
|
||
<?php
|
||
$intTotalnbSurListe+=fx_liste_attente_nombre_surliste($tabEpreuve['epr_id']);
|
||
echo ($nbSurListe = fx_liste_attente_nombre_surliste($tabEpreuve['epr_id'])) > 0 ? $nbSurListe : '';?>
|
||
|
||
|
||
</td>
|
||
</tr>
|
||
<?php
|
||
}
|
||
?>
|
||
</tbody>
|
||
<tfoot>
|
||
<tr>
|
||
<th> </th>
|
||
<th> </th>
|
||
<th id="qte_origine_total">
|
||
<?php echo $intTotalOriginal; ?>
|
||
</th>
|
||
<th id="qte_ajustement_total">
|
||
<?php echo $intTotalAjustement; ?>
|
||
</th>
|
||
<th id="qte_courante_total">
|
||
<?php echo $intTotalCurrent; ?>
|
||
</th>
|
||
<th id="qte_inscrits_total">
|
||
<?php echo $intTotalBooked; ?></th>
|
||
<th id="qte_restante_total">
|
||
<?php echo $intTotalAvailable; ?></th>
|
||
<th id="qte_checkin_total">
|
||
<?php echo $intTotalCheckin; ?></th>
|
||
<th>
|
||
</th>
|
||
<th id="qte_intTotalnbSurListe">
|
||
<?php echo $intTotalnbSurListea; ?>
|
||
</th>
|
||
|
||
<th id="qte_intTotalnbSurListea">
|
||
<?php echo $intTotalnbSurListe; ?>
|
||
</th>
|
||
|
||
|
||
|
||
</tr>
|
||
|
||
</tfoot>
|
||
<?php
|
||
?>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
function fxShowreglesniveau($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);
|
||
?>
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_reglesniveau')?></h2>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<a class="button-promoteur mb-2" style="background: url('<?php echo $vDomaine; ?>/images/plus-minus.png') no-repeat center" data-toggle="collapse" href="#collapseReglesNiveau" role="button" aria-expanded="false" aria-controls="collapseReglesNiveau">
|
||
<span class="d-inline-block h-100 w-100" data-toggle="tooltip" title="<?php afficheTexte('promoteur_div_tooltip')?>"></span>
|
||
</a>
|
||
<a class="btn btn-primary rounded-pill mb-2" href="<?php echo $vDomaine; ?>/inc_tableau_promoteur?promoteur_eve_id=<?php echo urlencode(base64_encode($int_eve_id)); ?>&resetcategorie=true">
|
||
recalculer les catégorie
|
||
</a>
|
||
</div>
|
||
<div class="animate__animated animate__fadeIn collapse" id="collapseReglesNiveau">
|
||
<div class="table-responsive-sm">
|
||
<table class="resultats" id="table_reglesniveau" style="width:100%;display: none">
|
||
<thead>
|
||
<tr class="HeaderRow" style="font-size:0.95em">
|
||
<td><?php afficheTexte('promoteur_qte_epr_id')?></td>
|
||
<td><?php afficheTexte('promoteur_qte_epr_type')?></td>
|
||
<td> </td>
|
||
|
||
<td> </td>
|
||
<td> </td> <td> </td> <td> </td> <td> </td>
|
||
<td> </td>
|
||
<td> </td> <td> </td>
|
||
<td> </td>
|
||
<td> </td><td> </td><td> </td>
|
||
|
||
|
||
|
||
|
||
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
$intTotalOriginal = $intTotalAvailable = $intTotalBooked = $intTotalCurrent = $intTotalAjustement = 0;
|
||
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++){
|
||
$tabEpreuve = fxGetEpreuve($tabEpreuves[$i]['epr_id']);
|
||
|
||
?>
|
||
<tr style="text-align: left;" class="<?php if ($i % 2) { ?>OddRow<?php } else { ?>EvenRow<?php } ?>">
|
||
<td> <?php echo $tabEpreuve['epr_id']?></td>
|
||
<td colspan="15"><?php
|
||
if (trim($tabEpreuve['epr_categorie_' . $strLangue]) != '') {
|
||
echo $tabEpreuve['epr_categorie_' . $strLangue] . " - ";
|
||
}
|
||
|
||
echo $tabEpreuve['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') {
|
||
echo " - " . $tabEpreuve['epr_nom_' . $strLangue];
|
||
}
|
||
?>
|
||
</td>
|
||
|
||
</tr>
|
||
<?php
|
||
$sqlRegles = "SELECT * FROM regles_niveau WHERE eve_id=".$int_eve_id." and epr_id=".$tabEpreuves[$i]['epr_id']." ORDER BY reg_niv,reg_trie";
|
||
$arrRegles = $objDatabase->fxGetResults($sqlRegles);
|
||
if ($arrRegles){
|
||
?> <tr style="background-color: #003580;color: white"><td></td><td colspan="15"> <?php if($tabEpreuve['epr_type_' . $strLangue] != '')
|
||
echo $tabEpreuve['epr_type_' . $strLangue];
|
||
if($tabEpreuve['epr_nom_' . $strLangue] != '')
|
||
echo $tabEpreuve['epr_nom_' . $strLangue]; ?></td> </tr> <?php
|
||
|
||
foreach ($arrRegles as $key => $value){
|
||
?>
|
||
|
||
<tr>
|
||
<td></td>
|
||
<td><?php echo $value['reg_niv']; ?></td>
|
||
<td><?php echo $value['reg_type']; ?></td>
|
||
<td><?php echo $value['reg_nom_'.$strLangue]; ?></td>
|
||
<td><?php echo $value['reg_param1']; ?></td>
|
||
<td><?php echo $value['reg_param2']; ?></td>
|
||
<td><?php echo $value['reg_param3']; ?></td>
|
||
<td><?php echo $value['reg_param4']; ?></td>
|
||
<td colspan="4"> </td>
|
||
</tr>
|
||
<?php
|
||
}
|
||
?> <tr style="background-color: #003580;color: white"><td colspan="16"> </td> </tr><?php
|
||
}
|
||
?>
|
||
|
||
|
||
|
||
<?php
|
||
}
|
||
?>
|
||
</tbody>
|
||
|
||
<?php
|
||
?>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
/*
|
||
* param $int_epr_id : le no. de l'epreuve a ajuster.
|
||
* param $strLangue : langue d'affichage
|
||
* */
|
||
function fxShowAjouterQuantite($int_epr_id, $intQte, $strLangue) {
|
||
global$vDomaine;
|
||
?>
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<input class="form-control form-control-sm rounded-0" type="number" min="0" maxlength="7" id="qte_restante_<?php echo $int_epr_id; ?>" value="<?php echo $intQte; ?>">
|
||
</div>
|
||
<div class="col-2">
|
||
<button class="btn_qte btn btn-primary btn-sm rounded-0" type="button" data-epr_id="<?php echo $int_epr_id; ?>" data-qte_initiale="<?php echo $intQte; ?>">OK</button>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
/** MSIN-4468 — Saisie de la capacité totale; le serveur la reconvertit en places restantes. */
|
||
function fxShowAjouterQuantiteTotaleV4($int_epr_id, $intQteTotale) {
|
||
?>
|
||
<div class="epr-gestion-qte-edit">
|
||
<input class="form-control epr-gestion-qte-input" type="number" min="0" max="9999999" id="qte_totale_<?php echo (int)$int_epr_id; ?>" value="<?php echo (int)$intQteTotale; ?>" aria-label="<?php echo fxBibEsc(afficheTexte('promoteur_qte_epr_qte_total', 0)); ?>">
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button class="btn_qte_total btn btn-primary btn-sm epr-gestion-qte-ok" type="button" data-epr_id="<?php echo (int)$int_epr_id; ?>" data-qte_initiale="<?php echo (int)$intQteTotale; ?>"><?php fxBibTexte('bib_v4_btn_ok', 1); ?></button>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_btn_ok'); ?>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
function fxShowBibTool2($str_code, $int_eve_id, $strLangue){
|
||
global $objDatabase, $vDomaine;
|
||
|
||
$sqlEpreuves = "SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = " . intval($int_eve_id) . " AND epr_actif = 1 ORDER BY epr_id";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
$sqlBibAssignments = "SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri";
|
||
$tabBibAssignments = $objDatabase->fxGetResults($sqlBibAssignments);
|
||
?>
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_bib_tool')?></h2>
|
||
</div>
|
||
<div class="card-body row text-center">
|
||
<div class="col-6 text-center">
|
||
<a class="button-promoteur" style="background: url('<?php echo $vDomaine; ?>/images/bib-icon.png') no-repeat center" data-toggle="collapse" href="#collapseBibTool" role="button" aria-expanded="false" aria-controls="collapseBibTool">
|
||
<span class="d-inline-block h-100 w-100" data-toggle="tooltip" title="<?php afficheTexte('promoteur_div_tooltip')?>"></span>
|
||
</a>
|
||
</div>
|
||
<div class="col-6 text-center">
|
||
<a class="button-promoteur" style="background: url('<?php echo $vDomaine; ?>/images/dupes.png') no-repeat center" href="<?php echo $vDomaine . "/" . $str_code; ?>bib_assignment?a=show_bib_dupes&eve_id=<?php echo urlencode(base64_encode($int_eve_id)); ?>" target="_blank">
|
||
<span class="d-inline-block h-100 w-100" data-toggle="tooltip" title="<?php afficheTexte('promoteur_div_tooltip')?>"></span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div class="collapse animate__animated animate__fadeIn" id="collapseBibTool">
|
||
<div class="table-responsive-sm">
|
||
<table class="table">
|
||
<thead>
|
||
<tr>
|
||
<th><?php afficheTexte('promoteur_bib_race')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_range_start')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_range_end')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_current')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_qte_ordered')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_assignment_type')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_actions')?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
for($i = 1; $i <= count($tabEpreuves); $i++){
|
||
$strClass = ($i & 1) ? '' : 'table-secondary';
|
||
|
||
if($tabEpreuves[$i]['epr_bib_start'] != 0)
|
||
$intBibStart = $tabEpreuves[$i]['epr_bib_start'];
|
||
else
|
||
$intBibStart = '';
|
||
|
||
if($tabEpreuves[$i]['epr_bib_finish'] != 0) {
|
||
$intToto = $tabEpreuves[$i]['epr_bib_finish'];
|
||
$sqlLastBib = "select max( cast(no_bib as unsigned) )from resultats_participants where epr_id = " . intval($tabEpreuves[$i]['epr_id']);
|
||
$intBibFinish = $objDatabase->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;
|
||
}
|
||
?>
|
||
<tr class="<?php echo $strClass ?>" style="text-align: center; font-size:1em">
|
||
<td>
|
||
<form name="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']?>" method="post" action="bib_assignment">
|
||
<input type="hidden" name="epr_id" value="<?php echo $tabEpreuves[$i]['epr_id']?>">
|
||
<input type="hidden" name="promoteur_eve_id" value="<?php echo $int_eve_id?>">
|
||
<input type="hidden" id="row_action_<?php echo $tabEpreuves[$i]['epr_id']?>" name="row_action_<?php echo $tabEpreuves[$i]['epr_id']?>" value="-">
|
||
</form>
|
||
<br>
|
||
<?php
|
||
if (trim($tabEpreuves[$i]['epr_categorie_' . $strLangue]) != '') {
|
||
echo $tabEpreuves[$i]['epr_categorie_' . $strLangue] . "<br>";
|
||
}
|
||
|
||
echo $tabEpreuves[$i]['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuves[$i]['epr_nom_' . $strLangue]) != '') {
|
||
echo "<br>" . $tabEpreuves[$i]['epr_nom_' . $strLangue];
|
||
}
|
||
?>
|
||
<br>
|
||
<div style="color:#ffa200; font-weight: bold">
|
||
<?php if($tabEpreuves[$i]['epr_equipe'] == 1)
|
||
afficheTexte('promoteur_epr_equipe');
|
||
else
|
||
afficheTexte('promoteur_epr_solo')?>
|
||
</div>
|
||
<br>
|
||
</td>
|
||
<td>
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" min="0" type="number" id="num_bib_range_start_<?php echo $tabEpreuves[$i]['epr_id']?>" name="num_bib_range_start_<?php echo $tabEpreuves[$i]['epr_id']?>" value="<?php echo $intBibStart ?>" disabled>
|
||
</td>
|
||
<td>
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" min="0" type="number" id="epr_bib_range_finish_dispo_<?php echo $tabEpreuves[$i]['epr_id']?>" name="num_bib_range_start_<?php echo $tabEpreuves[$i]['epr_id']?>" value="<?php echo $intBibFinishdispo ?>" disabled>
|
||
</td>
|
||
<td>
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" min="0" type="number" id="num_dernier_dossard_<?php echo $tabEpreuves[$i]['epr_id']?>" name="num_dernier_dossard_<?php echo $tabEpreuves[$i]['epr_id']?>" value="<?php echo $intBibFinish?>" disabled>
|
||
</td>
|
||
<td id="used_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>"><?php echo $intNbBibs?></td>
|
||
<td id="qty_booked_<?php echo $tabEpreuves[$i]['epr_id']; ?>">
|
||
<?php echo $intNbInscriptions?>
|
||
</td>
|
||
<td class="text-left">
|
||
<input type="hidden" name="epr_id" value="<?php echo $tabEpreuves[$i]['epr_id']?>"/>
|
||
|
||
<select form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" id="sel_assignment_type_<?php echo $tabEpreuves[$i]['epr_id']?>" name="sel_assignment_type_<?php echo $tabEpreuves[$i]['epr_id']; ?>" disabled>
|
||
<?php
|
||
for($j = 1; $j <= count($tabBibAssignments); $j++){
|
||
?>
|
||
<option <?php if($tabEpreuves[$i]['ba_id'] != 0 && $tabEpreuves[$i]['ba_id'] == $tabBibAssignments[$j]['ba_id']) echo 'selected="selected"'?> value="<?php echo $tabBibAssignments[$j]['ba_id']?>"><?php echo $tabBibAssignments[$j]['ba_nom_' . $strLangue]?></option>
|
||
<?php } ?>
|
||
</select>
|
||
<br>
|
||
<br>
|
||
<?php
|
||
if($tabEpreuves[$i]['epr_equipe'] == 1) {
|
||
?>
|
||
<div id="bib_options_bibandteam_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']?>" style="display: none;">
|
||
<div class="form-check">
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-check-input" type="checkbox" value="1" id="chk_bib_and_team_<?php echo $tabEpreuves[$i]['epr_id']; ?>" name="chk_bib_and_team"<?php if ($tabEpreuves[$i]['epr_bib_mode'] == 1) { ?> checked<?php } ?>>
|
||
<label class="form-check-label" for="chk_bib_and_team_<?php echo $tabEpreuves[$i]['epr_id']; ?>">
|
||
<?php afficheTexte('promoteur_bib_and_team_switch'); ?>
|
||
<button class="btn btn-sm rounded-circle" type="button" data-toggle="popover" data-content="<?php afficheTexte('promoteur_bib_bibandteam'); ?>">
|
||
<i class="fa fa-info-circle fa-2x text-info" aria-hidden="true"></i>
|
||
</button>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
if($tabEpreuves[$i]['epr_bib_finish'] != 0) {
|
||
?>
|
||
<div id="bib_options_fromlast_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']?>" style="display: none;">
|
||
<div class="form-check">
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-check-input" type="checkbox" value="1" id="chk_from_last_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" name="chk_from_last_bib">
|
||
<label class="form-check-label" for="chk_from_last_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>">
|
||
<?php afficheTexte('promoteur_bib_from_last'); ?>
|
||
<button class="btn btn-sm rounded-circle" type="button" data-toggle="popover" data-content="<?php afficheTexte('promoteur_bib_fromlastbib_tip'); ?>">
|
||
<i class="fa fa-info-circle fa-2x text-info" aria-hidden="true"></i>
|
||
</button>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<?php } ?>
|
||
</td>
|
||
<td>
|
||
<?php
|
||
if ($intNbBibs != 0) {
|
||
?>
|
||
<button class="btn btn-sm btn_bib btn-secondary mb-1 rounded-0" data-action="view" data-bib_type="<?php echo $tabEpreuves[$i]['ba_id']; ?>" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" id="btn_bib_view_<?php echo $tabEpreuves[$i]['epr_id']?>" title="<?php afficheTexte('promoteur_bib_view'); ?>" type="button">
|
||
<i class="fa fa-eye" aria-hidden="true"></i>
|
||
</button>
|
||
<?php } ?>
|
||
<button class="btn btn-sm btn_bib btn-secondary mb-2 rounded-0" data-action="edit" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="btn_bib_edit_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" title="<?php afficheTexte('promoteur_bib_edit'); ?>" type="button">
|
||
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
|
||
</button>
|
||
<br>
|
||
<button class="btn btn-sm btn_bib btn-success mb-1 rounded-0" data-action="assign" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="btn_bib_assign_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-eve_id="<?php echo $int_eve_id; ?>" data-toggle="tooltip" title="<?php afficheTexte('promoteur_bib_assign'); ?>" style="display: none;" type="button">
|
||
<i class="fa fa-plus-circle" aria-hidden="true"></i>
|
||
</button>
|
||
<br>
|
||
<button class="btn btn-sm btn_bib btn-danger mb-1 rounded-0" data-action="delete" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="btn_bib_delete_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" title="<?php afficheTexte('promoteur_bib_delete'); ?>" style="display: none;" type="button">
|
||
<i class="fa fa-minus-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
<?php } ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
function fxShowBibTool3($str_code, $int_eve_id, $strLangue){
|
||
global $objDatabase, $vDomaine;
|
||
|
||
$sqlEpreuves = "SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = " . intval($int_eve_id) . " AND epr_actif = 1 ORDER BY epr_id";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
$sqlBibAssignments = "SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri";
|
||
$tabBibAssignments = $objDatabase->fxGetResults($sqlBibAssignments);
|
||
|
||
|
||
?>
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_bib_tool')?></h2>
|
||
</div>
|
||
<div class="card-body row text-center">
|
||
|
||
|
||
</div>
|
||
<div >
|
||
<div class="table-responsive-sm">
|
||
<table class="table">
|
||
<thead>
|
||
<tr>
|
||
<th><?php afficheTexte('promoteur_bib_race')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_range_start')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_range_end_dispo')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_range_end')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_current')?></th>
|
||
<th><?php afficheTexte('promoteur_qte_epr_qte_ordered')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_assignment_type')?></th>
|
||
<th><?php afficheTexte('promoteur_bib_actions')?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
for($i = 1; $i <= count($tabEpreuves); $i++){
|
||
$strClass = ($i & 1) ? '' : 'table-secondary';
|
||
|
||
if($tabEpreuves[$i]['epr_bib_start'] != 0)
|
||
$intBibStart = $tabEpreuves[$i]['epr_bib_start'];
|
||
else
|
||
$intBibStart = '';
|
||
|
||
if($tabEpreuves[$i]['epr_bib_finish_dispo'] != 0)
|
||
$intBibFinishdispo= $tabEpreuves[$i]['epr_bib_finish_dispo'];
|
||
else
|
||
$intBibFinishdispo = '';
|
||
|
||
if($tabEpreuves[$i]['epr_bib_finish'] != 0) {
|
||
$intToto = $tabEpreuves[$i]['epr_bib_finish'];
|
||
$sqlLastBib = "select max( cast(no_bib as unsigned) )from resultats_participants where epr_id = " . intval($tabEpreuves[$i]['epr_id']);
|
||
$intBibFinish = $objDatabase->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;
|
||
}
|
||
?>
|
||
<tr class="<?php echo $strClass ?>" style="text-align: center; font-size:1em">
|
||
<td>
|
||
<form name="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']?>" method="post" action="bib_assignment">
|
||
<input type="hidden" name="epr_id" value="<?php echo $tabEpreuves[$i]['epr_id']?>">
|
||
<input type="hidden" name="promoteur_eve_id" value="<?php echo $int_eve_id?>">
|
||
<input type="hidden" id="row_action_<?php echo $tabEpreuves[$i]['epr_id']?>" name="row_action_<?php echo $tabEpreuves[$i]['epr_id']?>" value="-">
|
||
</form>
|
||
<br>
|
||
<?php
|
||
if (trim($tabEpreuves[$i]['epr_categorie_' . $strLangue]) != '') {
|
||
echo $tabEpreuves[$i]['epr_categorie_' . $strLangue] . "<br>";
|
||
}
|
||
|
||
echo $tabEpreuves[$i]['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuves[$i]['epr_nom_' . $strLangue]) != '') {
|
||
echo "<br>" . $tabEpreuves[$i]['epr_nom_' . $strLangue];
|
||
}
|
||
?>
|
||
<br>
|
||
<div style="color:#ffa200; font-weight: bold">
|
||
<?php
|
||
|
||
|
||
if($tabEpreuves[$i]['epr_equipe'] == 1)
|
||
afficheTexte('promoteur_epr_equipe');
|
||
else
|
||
afficheTexte('promoteur_epr_solo')?>
|
||
</div>
|
||
<br>
|
||
</td>
|
||
<td>
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" min="0" type="number" id="num_bib_range_start_<?php echo $tabEpreuves[$i]['epr_id']?>" name="num_bib_range_start_<?php echo $tabEpreuves[$i]['epr_id']?>" value="<?php echo $intBibStart ?>" disabled>
|
||
</td>
|
||
<td>
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" min="0" type="number" id="num_bib_range_finish_dispo_<?php echo $tabEpreuves[$i]['epr_id']?>" name="num_bib_range_finish_dispo_<?php echo $tabEpreuves[$i]['epr_id']?>" value="<?php echo $intBibFinishdispo ?>" disabled>
|
||
</td>
|
||
<td>
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" min="0" type="number" id="num_dernier_dossard_<?php echo $tabEpreuves[$i]['epr_id']?>" name="num_dernier_dossard_<?php echo $tabEpreuves[$i]['epr_id']?>" value="<?php echo $intBibFinish?>" disabled>
|
||
</td>
|
||
<td id="used_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>"><?php echo $intNbBibs?></td>
|
||
<td id="qty_booked_<?php echo $tabEpreuves[$i]['epr_id']; ?>">
|
||
<?php echo $intNbInscriptions?>
|
||
</td>
|
||
<td class="text-left">
|
||
<input type="hidden" name="epr_id" value="<?php echo $tabEpreuves[$i]['epr_id']?>"/>
|
||
<select form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-control form-control-sm rounded-0" id="sel_assignment_type_<?php echo $tabEpreuves[$i]['epr_id']?>" name="sel_assignment_type_<?php echo $tabEpreuves[$i]['epr_id']; ?>" disabled>
|
||
<?php
|
||
for($j = 1; $j <= count($tabBibAssignments); $j++){
|
||
?>
|
||
<option <?php if($tabEpreuves[$i]['ba_id'] != 0 && $tabEpreuves[$i]['ba_id'] == $tabBibAssignments[$j]['ba_id']) echo 'selected="selected"'?> value="<?php echo $tabBibAssignments[$j]['ba_id']?>"><?php echo $tabBibAssignments[$j]['ba_nom_' . $strLangue]?></option>
|
||
<?php } ?>
|
||
</select>
|
||
<br>
|
||
<br>
|
||
<?php
|
||
if($tabEpreuves[$i]['epr_equipe'] == 1) {
|
||
?>
|
||
<div id="bib_options_bibandteam_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']?>" style="display: none;">
|
||
<div class="form-check">
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-check-input" type="checkbox" value="1" id="chk_bib_and_team_<?php echo $tabEpreuves[$i]['epr_id']; ?>" name="chk_bib_and_team"<?php if ($tabEpreuves[$i]['epr_bib_mode'] == 1) { ?> checked<?php } ?>>
|
||
<label class="form-check-label" for="chk_bib_and_team_<?php echo $tabEpreuves[$i]['epr_id']; ?>">
|
||
<?php afficheTexte('promoteur_bib_and_team_switch'); ?>
|
||
<button class="btn btn-sm rounded-circle" type="button" data-toggle="popover" data-content="<?php afficheTexte('promoteur_bib_bibandteam'); ?>">
|
||
<i class="fa fa-info-circle fa-2x text-info" aria-hidden="true"></i>
|
||
</button>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
if($tabEpreuves[$i]['epr_bib_finish'] != 0) {
|
||
?>
|
||
<div id="bib_options_fromlast_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']?>" style="display: none;">
|
||
<div class="form-check">
|
||
<input form="frm_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" class="form-check-input" type="checkbox" value="1" id="chk_from_last_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>" name="chk_from_last_bib">
|
||
<label class="form-check-label" for="chk_from_last_bib_<?php echo $tabEpreuves[$i]['epr_id']; ?>">
|
||
<?php afficheTexte('promoteur_bib_from_last'); ?>
|
||
<button class="btn btn-sm rounded-circle" type="button" data-toggle="popover" data-content="<?php afficheTexte('promoteur_bib_fromlastbib_tip'); ?>">
|
||
<i class="fa fa-info-circle fa-2x text-info" aria-hidden="true"></i>
|
||
</button>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<?php } ?>
|
||
</td>
|
||
<td>
|
||
<?php
|
||
if ($intNbBibs != 0) {
|
||
?>
|
||
<button class="btn btn-sm btn_bib btn-secondary mb-1 rounded-0" data-action="view" data-bib_type="<?php echo $tabEpreuves[$i]['ba_id']; ?>" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" id="btn_bib_view_<?php echo $tabEpreuves[$i]['epr_id']?>" title="<?php afficheTexte('promoteur_bib_view'); ?>" type="button">
|
||
<i class="fa fa-eye" aria-hidden="true"></i>
|
||
</button>
|
||
<?php } ?>
|
||
<button class="btn btn-sm btn_bib btn-secondary mb-2 rounded-0" data-action="edit" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="btn_bib_edit_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" title="<?php afficheTexte('promoteur_bib_edit'); ?>" type="button">
|
||
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
|
||
</button>
|
||
<br>
|
||
<button class="btn btn-sm btn_bib btn-success mb-1 rounded-0" data-action="assign" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="btn_bib_assign_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" data-eve_id="<?php echo $int_eve_id; ?>" title="<?php afficheTexte('promoteur_bib_assign'); ?>" style="display: none;" type="button">
|
||
<i class="fa fa-plus-circle" aria-hidden="true"></i>
|
||
</button>
|
||
<br>
|
||
<button class="btn btn-sm btn_bib btn-danger mb-1 rounded-0" data-action="delete" data-epr_id="<?php echo $tabEpreuves[$i]['epr_id']; ?>" id="btn_bib_delete_<?php echo $tabEpreuves[$i]['epr_id']; ?>" data-toggle="tooltip" data-eve_id="<?php echo urlencode(base64_encode($int_eve_id)); ?>" title="<?php afficheTexte('promoteur_bib_delete'); ?>" style="display: none;" type="button">
|
||
<i class="fa fa-minus-circle" aria-hidden="true"></i>
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
<?php } ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
|
||
function fxGetAssignmentName($int_ba_id, $strLangue) {
|
||
global $objDatabase;
|
||
$sql = "SELECT ba_nom_" . $strLangue . " FROM bib_assignements WHERE ba_id = " . intval($int_ba_id);
|
||
return $objDatabase->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);
|
||
?>
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_reports_titre')?></h2>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<a class="button-promoteur" style="background: url('<?php echo $vDomaine; ?>/images/reports-icon.png') no-repeat center" data-toggle="collapse" href="#collapseRapports" role="button" aria-expanded="false" aria-controls="collapseRapports">
|
||
<span class="d-inline-block h-100 w-100" data-toggle="tooltip" title="<?php afficheTexte('promoteur_div_tooltip')?>"></span>
|
||
</a>
|
||
</div>
|
||
<div class="animate__animated animate__fadeIn collapse" id="collapseRapports">
|
||
<div class="card-body">
|
||
<ul class="list-unstyled">
|
||
<?php
|
||
if ($arrEvenement['te_id'] != 9) {
|
||
?>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/rapport_new.php?r=chrono&e=<?php echo urlencode(base64_encode($arrEvenement['eve_id'])); ?>&lng=<?php echo $strLangue; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i>chrono + questions
|
||
</a>
|
||
</li>
|
||
<?php
|
||
}
|
||
if ($arrEvenement['te_id'] == 13) {
|
||
?>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/rapport_new.php?r=adhesions&e=<?php echo urlencode(base64_encode($arrEvenement['eve_id'])); ?>&lng=<?php echo $strLangue; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i>adhésions actives
|
||
</a>
|
||
</li>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/rapport_new.php?r=adhesions-ventes&e=<?php echo urlencode(base64_encode($arrEvenement['eve_id'])); ?>&lng=<?php echo $strLangue; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i>liste d'adhésions annuelles
|
||
</a>
|
||
</li>
|
||
<?php
|
||
}
|
||
if ($arrEvenement['eve_rapport_finances_capitaines'] == 1) {
|
||
?>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/rapport_new.php?r=finances-pnq&e=<?php echo urlencode(base64_encode($arrEvenement['eve_id'])); ?>&lng=<?php echo $strLangue; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i>Transactions-Finances (capitaines seulement)
|
||
</a>
|
||
</li>
|
||
<?php
|
||
}
|
||
?>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/rapport_new.php?r=finances<?php if ($arrEvenement['te_id'] == 13) { ?>-membership<?php } ?>&e=<?php echo urlencode(base64_encode($arrEvenement['eve_id'])); ?>&lng=<?php echo $strLangue; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i>Transactions-Finances
|
||
</a>
|
||
</li>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/rapport_new.php?r=remboursements&e=<?php echo urlencode(base64_encode($arrEvenement['eve_id'])); ?>&lng=<?php echo $strLangue; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i><?php if($strLangue == 'fr') echo "Paiements"; else echo "Payments"?>
|
||
</a>
|
||
</li>
|
||
<?php
|
||
for ($intCtr = 1; $intCtr <= count($tabRapports); $intCtr++) {
|
||
?>
|
||
<li class="mb-2">
|
||
<a class="btn btn-primary rounded-pill" href="<?php echo $vDomaine; ?>/superadm/index.php?t=<?php echo urlencode(base64_encode(fxUnescape($tabRapports[$intCtr]['men_id']))); ?>&a=report&lng=<?php echo $strLangue; ?>" data-toto="<?php echo $intCtr; ?>" target="_blank">
|
||
<i class="fa fa-bar-chart mr-2" aria-hidden="true"></i><?php echo fxUnescape($tabRapports[$intCtr]['men_nom']); ?>
|
||
</a>
|
||
</li>
|
||
<?php
|
||
}
|
||
?>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
function fxShowDupes($int_eve_id) {
|
||
global $strLangue, $objDatabase, $vDomaine;
|
||
|
||
if ($strLangue == 'fr') {
|
||
$strPage = '/compte';
|
||
} else {
|
||
$strPage = '/account';
|
||
}
|
||
|
||
$sqlNoBib = "SELECT no_bib, epr_id, COUNT(*) c FROM resultats_participants where eve_id = " . intval($int_eve_id) . " AND no_bib <> '' AND is_cancelled = 0 GROUP BY no_bib, epr_id HAVING c > 1";
|
||
$tabIntraDupes = $objDatabase->fxGetResults($sqlNoBib);
|
||
|
||
$tabInterDupes = [];
|
||
if (!fxBibEventAllowsInterEprDuplicates((int)$int_eve_id)) {
|
||
$sqlInter = "SELECT no_bib FROM resultats_participants WHERE eve_id = " . intval($int_eve_id)
|
||
. " AND no_bib <> '' AND is_cancelled = 0 GROUP BY no_bib HAVING COUNT(DISTINCT epr_id) > 1";
|
||
$tabInterDupes = $objDatabase->fxGetResults($sqlInter);
|
||
}
|
||
|
||
$tabBibKeys = [];
|
||
if (is_array($tabIntraDupes)) {
|
||
foreach ($tabIntraDupes as $row) {
|
||
$tabBibKeys[(int)$row['no_bib']] = true;
|
||
}
|
||
}
|
||
if (is_array($tabInterDupes)) {
|
||
foreach ($tabInterDupes as $row) {
|
||
$tabBibKeys[(int)$row['no_bib']] = true;
|
||
}
|
||
}
|
||
?>
|
||
<div class="box_participant card mb-3">
|
||
|
||
<div class="card-body">
|
||
<div class="card-header">
|
||
<h2><?php afficheTexte('promoteur_bib_dupes'); ?></h2>
|
||
</div>
|
||
<div class="card-body">
|
||
<table class="table table-striped" id="table_dupes">
|
||
<thead>
|
||
<tr>
|
||
<th><?php afficheTexte('promoteur_bib_number'); ?></th>
|
||
<th><?php afficheTexte('promoteur_bib_participant'); ?></th>
|
||
<th><?php afficheTexte("promoteur_bib_race"); ?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
if (!empty($tabBibKeys)) {
|
||
$intCtr = 1;
|
||
|
||
foreach (array_keys($tabBibKeys) as $intNoBib) {
|
||
$sqlDupes = "select par_prenom, par_nom, epr_id from resultats_participants where eve_id = " . intval($int_eve_id) . " and is_cancelled = 0 and no_bib = " . intval($intNoBib);
|
||
$tabDupes = $objDatabase->fxGetResults($sqlDupes);
|
||
|
||
if ($tabDupes != null) {
|
||
foreach ($tabDupes as $dupe) {
|
||
$tabEpreuve = fxGetEpreuve($dupe['epr_id']);
|
||
?>
|
||
<tr>
|
||
<td><?php echo (int)$intNoBib; ?></td>
|
||
<td><?php echo $dupe['par_prenom'] . " " . $dupe['par_nom']; ?></td>
|
||
<td>
|
||
<?php
|
||
if (trim($tabEpreuve['epr_categorie_' . $strLangue]) != '') {
|
||
echo $tabEpreuve['epr_categorie_' . $strLangue] . "<br>";
|
||
}
|
||
|
||
echo $tabEpreuve['epr_type_' . $strLangue];
|
||
|
||
if (trim($tabEpreuve['epr_nom_' . $strLangue]) != '') {
|
||
echo "<br>" . $tabEpreuve['epr_nom_' . $strLangue];
|
||
}
|
||
|
||
echo " (" . $tabEpreuve['epr_id'] . ")";
|
||
|
||
?>
|
||
</td>
|
||
</tr>
|
||
<?php
|
||
}
|
||
$intCtr++;
|
||
}
|
||
}
|
||
} else {
|
||
?>
|
||
<td colspan="3"><?php afficheTexte('promoteur_no_dupes'); ?></td>
|
||
<?php
|
||
}
|
||
?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
</div>
|
||
|
||
<?php
|
||
}
|
||
|
||
function fxShowBibNumbersTable($tab_epreuve, $strLangue, $intEveId = 0) {
|
||
global $objDatabase, $vDomaine;
|
||
|
||
if ($strLangue == 'fr') {
|
||
$strPage = '/compte';
|
||
} else {
|
||
$strPage = '/account';
|
||
}
|
||
|
||
$sqlTri = "SELECT * FROM bib_assignements WHERE ba_id = " . intval($tab_epreuve['ba_id']);
|
||
$intTri = $objDatabase->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);
|
||
?>
|
||
<div class="box_participant card mb-3">
|
||
<div class="card-header">
|
||
<h2>
|
||
<?php afficheTexte('promoteur_bib_resultats'); ?>
|
||
<br>
|
||
<small>
|
||
<?php echo "(" . fxGetAssignmentName($tab_epreuve['ba_id'], $strLangue) . ")"; ?>
|
||
</small>
|
||
</h2>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<div class="card-body">
|
||
<table class="table table-striped" id="table_bibs">
|
||
<thead>
|
||
<tr>
|
||
<th class="text-left"><?php afficheTexte("promoteur_bib_race"); ?></th>
|
||
<th class="text-left">
|
||
<?php
|
||
if ($tab_epreuve['epr_equipe'] == 1) {
|
||
afficheTexte('promoteur_bib_equipe');
|
||
} else {
|
||
afficheTexte('promoteur_bib_participant');
|
||
}
|
||
?>
|
||
</th>
|
||
<th class="text-left">
|
||
<?php
|
||
if ($tab_epreuve['epr_equipe'] == 1) {
|
||
afficheTexte('promoteur_bib_no_equipe');
|
||
} else {
|
||
afficheTexte('promoteur_bib_no_participants');
|
||
}
|
||
?>
|
||
</th>
|
||
<?php if ($tab_epreuve['epr_equipe'] == 1) { ?>
|
||
<th class="text-left"><?php afficheTexte('promoteur_bib_no_teammates'); ?></th>
|
||
<?php } ?>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
if ($tab_epreuve['epr_equipe'] == 0) {
|
||
if ($tabInscriptions != null) {
|
||
for ($i = 1;$i <= count($tabInscriptions);$i++){
|
||
// ne pas afficher les volunteers/pit managers
|
||
if ($tabInscriptions[$i]['rol_id'] != 3 && $tabInscriptions[$i]['rol_id'] != 4){
|
||
?>
|
||
<tr class="<?php if ($i % 2) echo "EvenRow"; else echo "OddRow";?>">
|
||
<td>
|
||
<?php
|
||
if ($tab_epreuve['epr_nom_' . $strLangue] != '')
|
||
echo $tab_epreuve['epr_nom_' . $strLangue];
|
||
echo "<br>";
|
||
if ($tab_epreuve['epr_type_' . $strLangue] != '')
|
||
echo $tab_epreuve['epr_type_' . $strLangue];
|
||
|
||
echo " (" . $tab_epreuve['epr_id'] . ")";
|
||
?>
|
||
</td>
|
||
<td><?php echo $tabInscriptions[$i]['par_prenom'] . " " . $tabInscriptions[$i]['par_nom']?></td>
|
||
<td><?php echo $tabInscriptions[$i]['no_bib']?></td>
|
||
</tr>
|
||
<?php }
|
||
}?>
|
||
|
||
<?php
|
||
}
|
||
}
|
||
elseif($tab_epreuve['epr_equipe'] == 1){
|
||
for ($i = 1; $i <= count($tabEpreuvesCommandees); $i++){
|
||
?>
|
||
<tr class="<?php if ($i % 2) echo "EvenRow"; else echo "OddRow";?>">
|
||
<td>
|
||
<?php
|
||
if ($tab_epreuve['epr_nom_' . $strLangue] != '')
|
||
echo $tab_epreuve['epr_nom_' . $strLangue];
|
||
echo "<br>";
|
||
if ($tab_epreuve['epr_type_' . $strLangue] != '')
|
||
echo $tab_epreuve['epr_type_' . $strLangue];
|
||
|
||
echo " (" . $tab_epreuve['epr_id'] . ")";
|
||
?>
|
||
</td>
|
||
<td><?php echo $tabEpreuvesCommandees[$i]['pec_nom_equipe']?></td>
|
||
<td><?php echo $tabEpreuvesCommandees[$i]['no_equipe']?></td>
|
||
<td>
|
||
<ul><?php
|
||
// get team members
|
||
$sqlEquipe = "SELECT * FROM resultats_participants p WHERE pec_id = " . intval($tabEpreuvesCommandees[$i]['pec_id_original']) . " ORDER BY no_bib";
|
||
$tabEquipe = $objDatabase->fxGetResults($sqlEquipe);
|
||
for($j = 1; $j <= count($tabEquipe); $j++){
|
||
if($tabEquipe[$j]['rol_id'] != 3 && $tabEquipe[$j]['rol_id'] != 4) {
|
||
?>
|
||
<li><?php echo $tabEquipe[$j]['no_bib'] . " - " . $tabEquipe[$j]['par_prenom'] . " " . $tabEquipe[$j]['par_nom'];?></li>
|
||
<?php
|
||
}
|
||
}
|
||
?>
|
||
</ul></td></tr>
|
||
<?php
|
||
}
|
||
} else {
|
||
echo "Nothing found.";
|
||
}
|
||
?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
// sl ($intEveId != 0)
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
function fxSetBibNumbers($tab_data, $int_epr_id, $int_start, $int_finish, $int_type, $int_par_equipe, $str_action = '', $int_mode,$int_finish_dispo=999999) {
|
||
global $strLangue, $objDatabase, $vDomaine;
|
||
|
||
// MSIN-4464 — audit dossards batch
|
||
if (!function_exists('fxFicheAuditRecordChange')) {
|
||
require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php';
|
||
}
|
||
|
||
if ($strLangue == 'fr') {
|
||
$strPage = '/compte';
|
||
} else {
|
||
$strPage = '/account';
|
||
}
|
||
|
||
if ($str_action == 'reset') {
|
||
$blnError = false;
|
||
// reset tables
|
||
// inscriptions_epreuves
|
||
$sqlUpdate = "UPDATE inscriptions_epreuves SET epr_bib_start = 0, epr_bib_finish = 0, epr_bib_mode = 0, ba_id = 2 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 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, par_maj = '" . fxGetDateTime() . "' 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) {
|
||
?>
|
||
<div class="error">Reset Problems - Try again</div>
|
||
<?php
|
||
} else {
|
||
?>
|
||
<div class="box_participant card mb-3">
|
||
<div class="card-header">
|
||
<h2>
|
||
<?php
|
||
if ($tab_data['epr_nom_' . $strLangue] != '')
|
||
echo $tab_data['epr_nom_' . $strLangue];
|
||
?>
|
||
<br>
|
||
<small>
|
||
<?php
|
||
if ($tab_data['epr_type_' . $strLangue] != '')
|
||
echo $tab_data['epr_type_' . $strLangue];
|
||
|
||
echo " (" . $tab_data['epr_id'] . ")";
|
||
?>
|
||
</small>
|
||
</h2>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<?php afficheTexte('promoteur_bib_reset_result'); ?>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<?php
|
||
}
|
||
} else {
|
||
if(isset($_POST['chk_from_last_bib'])) {
|
||
$intNoBib = $_POST['num_dernier_dossard_' . $_POST['epr_id']] + 1;
|
||
// set where (pour MSIN-1563 et al.)
|
||
$strWhere = " AND p.no_bib = ''";
|
||
} else {
|
||
$intNoBib = $int_start;
|
||
$strWhere = '';
|
||
}
|
||
$intCtr = 0;
|
||
|
||
// set ORDER By
|
||
switch ($int_type) {
|
||
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($int_epr_id) . $strWhere . $strOrderBy;
|
||
|
||
// $sqlInscriptions = "SELECT * FROM resultats_participants p WHERE p.is_cancelled = 0 AND p.epr_id = " . intval($int_epr_id) . $strOrderBy;
|
||
$tabInscriptions = $objDatabase->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) {
|
||
$intParBatch = intval($tabInscriptions[$i]['par_id']);
|
||
$strOldBibBatch = (string)($tabInscriptions[$i]['no_bib'] ?? '');
|
||
$strNewBibBatch = ($str_action == 'reset') ? '' : (string)($intNoBib + $intCtr);
|
||
$sqlUpdate = "UPDATE resultats_participants ";
|
||
if ($str_action == 'reset') {
|
||
// MSIN-4328 — par_maj pour repousser vers ChronoTrack
|
||
$sqlUpdate .= "SET no_bib = '', par_date_bib = null, par_maj = '" . fxGetDateTime() . "'";
|
||
// $sqlUpdate .= "SET no_bib = ''";
|
||
} else {
|
||
if($tabInscriptions[$i]['par_date_bib'] == null){
|
||
$sqlUpdate .= "SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "', par_maj = '" . fxGetDateTime() . "'";
|
||
} else{
|
||
$sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "', 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']);
|
||
} else {
|
||
fxFicheAuditRecordChange(
|
||
$intParBatch,
|
||
'no_bib',
|
||
$strOldBibBatch,
|
||
$strNewBibBatch,
|
||
($str_action == 'reset') ? 'bib_batch_reset' : 'bib_batch',
|
||
intval($tabInscriptions[$i]['eve_id'] ?? 0)
|
||
);
|
||
}
|
||
|
||
$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;
|
||
}
|
||
$intParEqBatch = intval($tabEquipe[$j]['par_id']);
|
||
$strOldBibEq = (string)($tabEquipe[$j]['no_bib'] ?? '');
|
||
$strNewBibEq = (string)$intNoBib;
|
||
if($tabInscriptions[$i]['par_date_bib'] == null){
|
||
$sqlUpdatePart = "UPDATE resultats_participants SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib). "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . $intParEqBatch;
|
||
} else{
|
||
// MSIN-4328 — par_maj pour repousser vers ChronoTrack
|
||
$sqlUpdatePart = "UPDATE resultats_participants SET no_bib = '" . $objDatabase->fxEscape($intNoBib) . "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . $intParEqBatch;
|
||
}
|
||
$qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart);
|
||
if (!$qryUpdatePart) {
|
||
fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']);
|
||
} else {
|
||
fxFicheAuditRecordChange(
|
||
$intParEqBatch,
|
||
'no_bib',
|
||
$strOldBibEq,
|
||
$strNewBibEq,
|
||
'bib_batch',
|
||
intval($tabEquipe[$j]['eve_id'] ?? 0)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
$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 = '
|
||
<div class="row">
|
||
<div class="col-10">
|
||
' . $m_membre . '
|
||
</div>
|
||
<div class="col-2">
|
||
|
||
</div>
|
||
</div>
|
||
';
|
||
} 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 = '
|
||
<div class="row">
|
||
<div class="col-12 lbl_hint">
|
||
';
|
||
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 .= '
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-10">
|
||
<input class="form-control form-control-sm rounded-0" type="number" id="' . $strId . $arrListeParticipants[$x]['par_id'] . '" name="txt_no_bib_' . $arrListeParticipants[$x]['par_id'] . '" min="0" required value="' . $intValue . '">
|
||
</div>
|
||
<div class="col-2">
|
||
<button class="btn btn_bib btn-sm btn-primary rounded-0" type="button" data-action="' . $strAction . '" data-eve_id="' . urlencode(base64_encode($arrListeParticipants[$x]['eve_id'])) . '" data-epr_id="' . $arrListeParticipants[$x]['epr_id'] . '" data-par_id="' . $arrListeParticipants[$x]['par_id'] . '" data-pec_id="' . $arrListeParticipants[$x]['pec_id_original'] . '" id="btn_no_bib_' . $arrListeParticipants[$x]['par_id'] . '" name="btn_no_bib_' . $arrListeParticipants[$x]['par_id'] . '" data-toggle0="tooltip" title="' . afficheTexte('promoteur_bib_tip', 0) . '">OK</button>
|
||
</div>
|
||
</div>
|
||
';
|
||
|
||
}
|
||
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 (transferee / annulee).
|
||
$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';
|
||
} else {
|
||
$strBadgeLbl = ($strLangue == 'fr') ? 'Annulée' : 'Cancelled';
|
||
}
|
||
$strCancelBadge = '<div class="mb-2"><span class="inscr-gestion-cancel-badge inscr-gestion-cancel-badge--' . $strCause . '">' . htmlspecialchars($strBadgeLbl, ENT_QUOTES, 'UTF-8') . '</span></div>';
|
||
}
|
||
|
||
$strAffichage = $strCancelBadge . '
|
||
<button class="btn btn-primary btn-sm btn-block rounded-0 btn_edit_event_promo' . $strStyleEdit . '" id="modifier_' . $x . '" data-eve_code="' . $strCode . '" data-epr_id="' . $arrListeParticipants[$x]['epr_id'] . '" data-eve_id="' . $arrListeParticipants[$x]['eve_id'] . '" value="' . $arrListeParticipants[$x]['pec_id_original'] . '">' . afficheTexte('btn_modifierinscriptions', 0) . '</button>
|
||
<button class="btn btn-secondary btn-sm btn-block rounded-0 btn_cancel_event_promo' . $strStyleCancel . '" id="annuler_' . $x . '" type="button" data-eve_code="' . $strCode . '" data-epr_id="' . $arrListeParticipants[$x]['epr_id'] . '" data-eve_id="' . $arrListeParticipants[$x]['eve_id'] . '" value="' . $arrListeParticipants[$x]['pec_id_original'] . '">' . afficheTexte('btn_annulerinscriptions', 0) . '</button>
|
||
<button class="btn btn-secondary btn-sm btn-block rounded-0 btn_retablir_event_promo' . $strStyleRetablir . '" id="retablir_' . $x . '" type="button" data-eve_code="' . $strCode . '" data-epr_id="' . $arrListeParticipants[$x]['epr_id'] . '" data-eve_id="' . $arrListeParticipants[$x]['eve_id'] . '" value="' . $arrListeParticipants[$x]['pec_id_original'] . '">' . afficheTexte('btn_retablirinscriptions', 0) . '</button>
|
||
';
|
||
|
||
|
||
|
||
|
||
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 = '<i class="fa fa-check" aria-hidden="true"></i>';
|
||
} else {
|
||
$strChecked = "";
|
||
$intValeur = 1;
|
||
$strClass = 'btn-primary';
|
||
$strImage = '<i class="fa fa-sharp fa-regular fa-square fa-2xs" aria-hidden="true"></i>';
|
||
}
|
||
|
||
|
||
|
||
if ($intEquipe == 1 && fxIsParEquipe($arrListeParticipants[$x]['pec_id_original'], $arrListeParticipants[$x]['epr_id'])) {
|
||
$strAffichage .= '
|
||
<button class="btn btn-secondary btn-sm btn_teammates rounded-0" type="button" data-eve_id="' . $arrListeParticipants[$x]['eve_id'] . '" data-epr_id="' . $arrListeParticipants[$x]['epr_id'] . '" data-pec_id="' . $arrListeParticipants[$x]['pec_id'] . '" data-toggle="modal" data-target="#modal_teammates">
|
||
' . afficheTexte('promoteur_bib_show_teamates', 0) . '
|
||
</button>
|
||
';
|
||
} 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 .='</br><hr>'.afficheTexte('promoteur_bib_enregistre', 0).'</br><span id="'.$arrListeParticipants[$x]['par_id'].'"><a class="btn btn-sm rounded-0 btn_remis '.$strClass.' " href="#" data-action="remis" data-table="'.urlencode(base64_encode('resultats_participants')).'" data-field="no_bib_remis" data-key="par_id" data-valeur="'.$intValeur.'" data-id="'.$arrListeParticipants[$x]['par_id'] .'">'. $strImage.' </a>
|
||
</span>';
|
||
$strAffichage .='</div>';
|
||
$strAffichage .=' </br> </div>';
|
||
$strAffichage .='<div id="date_'.$arrListeParticipants[$x]['par_id'].'" class="col-12 lbl_hint row">';
|
||
$strAffichage .=$arrListeParticipants[$x]['no_bib_remis_date'];
|
||
$strAffichage .='</br></div>';
|
||
$strAffichage .='<div id="par_'.$arrListeParticipants[$x]['par_id'].'" class="col-12 lbl_hint row">';
|
||
$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 .= '<br>';
|
||
}
|
||
|
||
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 .= '<br>';
|
||
}
|
||
|
||
$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 .= '<td class="text-' . $arrCol['align'] . '">' . $strAffichage . '</td>';
|
||
}
|
||
|
||
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' => '<strong>{0}</strong>{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' => '<a class="btn btn-primary rounded-pill btn-sm" href="' . $vDomaine . '/facture.php?no_panier={0}&lang=' . $strLangue . '" target="_blank">{1}</a>',
|
||
'multilingue' => 0,
|
||
'label_fr' => '# commande',
|
||
'label_en' => 'Order #'
|
||
),
|
||
7 => array(
|
||
'field' => 'pd_recu_pdf',
|
||
'align' => 'left',
|
||
'format' => 'string',
|
||
'mask' => '<a class="btn btn-primary rounded-pill btn-sm" href="' . $vDomaine . $vRepertoireFichiers . '/pdf/dons/{0}" target="_blank">PDF</a>',
|
||
'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' => '<strong>{0}</strong>{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' => '<a class="btn btn-primary rounded-pill btn-sm" href="' . $vDomaine . '/facture.php?no_panier={0}&lang=' . $strLangue . '" target="_blank">{1}</a><br>',
|
||
'multilingue' => 0,
|
||
'label_fr' => '# commande',
|
||
'label_en' => 'Order #'
|
||
),
|
||
8 => array(
|
||
'field' => 'no_panier,no_commande',
|
||
'align' => 'left',
|
||
'format' => 'confirm',
|
||
'mask' => '<button class="btn btn-primary rounded-0 btn-sm link_confirmation" data-no_panier="{0}" data-no_commande="{1}" data-lng="' . $strLangue . '">' . $strRenvoi . '</button>',
|
||
'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);
|
||
|
||
// MSIN-4464 — audit dossard (apres UPDATE reussi uniquement).
|
||
if (!function_exists('fxFicheAuditRecordChange')) {
|
||
require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php';
|
||
}
|
||
|
||
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';
|
||
}
|
||
|
||
$strOldBib = (string)$objDatabase->fxGetVar(
|
||
'SELECT no_bib FROM resultats_participants WHERE par_id = ' . intval($intPartipcipant) . ' LIMIT 1'
|
||
);
|
||
$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);
|
||
}
|
||
fxFicheAuditRecordChange(
|
||
intval($intPartipcipant),
|
||
'no_bib',
|
||
$strOldBib,
|
||
fxUnescape($strBib),
|
||
'bib_manuel',
|
||
intval($intEveId)
|
||
);
|
||
$arrRetour['state'] = 'success';
|
||
}
|
||
} elseif($tabEpreuve['epr_equipe'] == 1 && $tabEpreuve['epr_bib_mode'] == 0) {
|
||
$strOldBib = (string)$objDatabase->fxGetVar(
|
||
'SELECT no_bib FROM resultats_participants WHERE par_id = ' . intval($intPartipcipant) . ' LIMIT 1'
|
||
);
|
||
$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);
|
||
}
|
||
fxFicheAuditRecordChange(
|
||
intval($intPartipcipant),
|
||
'no_bib',
|
||
$strOldBib,
|
||
(string)$intNewNoBib,
|
||
'bib_manuel',
|
||
intval($intEveId)
|
||
);
|
||
$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++) {
|
||
$intParTeam = intval($tabTeam[$i]['par_id']);
|
||
$strOldBibTeam = (string)($tabTeam[$i]['no_bib'] ?? '');
|
||
$strNewBibTeam = '';
|
||
if ($strAction == 'no_equipe' && $tabEpreuve['epr_bib_mode'] == 0) {
|
||
if (intval($tabTeam[$i]['rol_id']) == 1) {
|
||
$strNewBibTeam = (string)(intval($strBib) * 10);
|
||
$sqlUpdatePart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = " . intval($strBib) * 10 . ", par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . $intParTeam;
|
||
} else {
|
||
$strNewBibTeam = (string)$strBib . $intCtr;
|
||
$sqlUpdatePart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = '" . $strBib . $intCtr . "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . $intParTeam;
|
||
$intCtr++;
|
||
}
|
||
|
||
$qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart);
|
||
|
||
if (!$qryUpdate) {
|
||
fxcreer_log("Erreur durant assignation manuelle du numero d'équipe (" . $intEpreuveCommandee . ")");
|
||
} elseif ($qryUpdatePart) {
|
||
fxFicheAuditRecordChange(
|
||
$intParTeam,
|
||
'no_bib',
|
||
$strOldBibTeam,
|
||
$strNewBibTeam,
|
||
'bib_equipe',
|
||
intval($intEveId)
|
||
);
|
||
}
|
||
} else {
|
||
$strNewBibTeam = (string)$strBib;
|
||
$sqlUpdatePart = "UPDATE resultats_participants SET par_modification_promoteur = 1, no_bib = '" . $strBib . "', par_maj = '" . fxGetDateTime() . "' WHERE par_id = " . $intParTeam;
|
||
$qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart);
|
||
|
||
if (!$qryUpdatePart) {
|
||
fxcreer_log("Erreur durant assignation manuelle du numero de dossard (" . $intPartipcipant . ")");
|
||
} else {
|
||
fxFicheAuditRecordChange(
|
||
$intParTeam,
|
||
'no_bib',
|
||
$strOldBibTeam,
|
||
$strNewBibTeam,
|
||
'bib_equipe',
|
||
intval($intEveId)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
// MSIN-4464 — ancienne valeur avant UPDATE.
|
||
$rowAvant = $objDatabase->fxGetRow(
|
||
'SELECT par_statut_course, eve_id FROM resultats_participants WHERE par_id = ' . $intParId . ' LIMIT 1'
|
||
);
|
||
$strOldStatut = is_array($rowAvant) ? trim((string)($rowAvant['par_statut_course'] ?? '')) : '';
|
||
$intEveId = is_array($rowAvant) ? intval($rowAvant['eve_id'] ?? 0) : 0;
|
||
|
||
$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)) {
|
||
if (!function_exists('fxFicheAuditRecordChange')) {
|
||
require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php';
|
||
}
|
||
fxFicheAuditRecordChange($intParId, 'par_statut_course', $strOldStatut, $strCode, 'statut', $intEveId);
|
||
$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 .= '
|
||
<div class="form-group row">
|
||
<label for="txt_no_bib_tm_' . $tabEquipe[$i]['par_id'] . '" class="col-md-4 col-form-label">
|
||
' . fxUnescape($tabEquipe[$i]['par_prenom']) . ' ' . fxUnescape($tabEquipe[$i]['par_nom']) . '
|
||
</label>
|
||
<div class="col-10 col-md-6">
|
||
<input class="form-control form-control-sm rounded-0" type="number" id="txt_no_bib_p' . $tabEquipe[$i]['par_id'] . '" name="txt_no_bib_' . $tabEquipe[$i]['par_id'] . '" min="0" required value="' . $tabEquipe[$i]["no_bib"] . '">
|
||
</div>
|
||
<div class="col-2">
|
||
<button class="btn btn_bib btn-sm btn-primary rounded-0" type="button" data-action="no_bib" data-eve_id="' . urlencode(base64_encode($tabEquipe[$i]['eve_id'])) . '" data-epr_id="' . $tabEquipe[$i]['epr_id'] . '" data-par_id="' . $tabEquipe[$i]['par_id'] . '" data-pec_id="' . $tabEquipe[$i]['pec_id_original'] . '" id="btn_no_bib_' . $tabEquipe[$i]['par_id'] . '" name="btn_no_bib_' . $tabEquipe[$i]['par_id'] . '" data-toggle="tooltip" title="' . afficheTexte('promoteur_bib_tip', 0) . '">OK</button>
|
||
</div>
|
||
</div>
|
||
';
|
||
}
|
||
|
||
$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;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4468 — Reçoit une capacité totale claire pour l'utilisateur, tout en
|
||
* conservant epr_qte comme stock restant attendu par le moteur historique.
|
||
*/
|
||
function fxUpdateQuantiteTotale($intEpreuve, $intQuantiteTotale) {
|
||
global $objDatabase;
|
||
|
||
$arrRetour = array('state' => 'error');
|
||
$intEpreuve = intval($intEpreuve);
|
||
$intQuantiteTotale = intval($intQuantiteTotale);
|
||
|
||
if ($intEpreuve <= 0 || $intQuantiteTotale < 0) {
|
||
return $arrRetour;
|
||
}
|
||
|
||
$tabEpreuve = fxGetEpreuve($intEpreuve);
|
||
if ($tabEpreuve == null || intval($tabEpreuve['epr_qte_limitee']) !== 1) {
|
||
return $arrRetour;
|
||
}
|
||
|
||
$arrQuantites = fxGetQuantites($intEpreuve);
|
||
$intNbInscriptions = intval($arrQuantites['qte_inscrits'] ?? 0);
|
||
if ($intQuantiteTotale < $intNbInscriptions) {
|
||
$arrRetour['error_code'] = 'total_below_registrations';
|
||
$arrRetour['qte_inscrits'] = $intNbInscriptions;
|
||
return $arrRetour;
|
||
}
|
||
|
||
$intAncienneQte = intval($tabEpreuve['epr_qte']);
|
||
$intNouvelleQte = $intQuantiteTotale - $intNbInscriptions;
|
||
$intDifference = $intNouvelleQte - $intAncienneQte;
|
||
|
||
if ($intDifference !== 0) {
|
||
// Refuse d'écraser un stock qui aurait changé depuis sa lecture.
|
||
$sqlUpdate = "UPDATE inscriptions_epreuves"
|
||
. " SET epr_qte_ajoutee = epr_qte_ajoutee + " . intval($intDifference)
|
||
. ", epr_qte = epr_qte + " . intval($intDifference)
|
||
. " WHERE epr_id = " . $intEpreuve
|
||
. " AND epr_qte_limitee = 1"
|
||
. " AND epr_qte = " . $intAncienneQte;
|
||
$qryUpdate = $objDatabase->fxQuery($sqlUpdate);
|
||
|
||
if (!$qryUpdate || intval($objDatabase->fxGetNbAffectedRows()) !== 1) {
|
||
return $arrRetour;
|
||
}
|
||
}
|
||
|
||
$arrRetour['data'] = fxGetQuantitesEvenement($intEpreuve);
|
||
$arrRetour['state'] = 'success';
|
||
|
||
return $arrRetour;
|
||
}
|
||
|
||
|
||
// v2 — encart « choisissez vos séquences » (batch + auto)
|
||
function renderBibBatchPickPrompt() {
|
||
ob_start();
|
||
?>
|
||
<div class="bib-seq-pick-prompt batch-pick-prompt bib-ui-hidden">
|
||
<p class="batch-pick-prompt__title"><?php fxBibTexteTrad('bib_v4_batch_pick_title', 1); ?></p>
|
||
<p class="batch-pick-prompt__hint text-muted mb-0"><?php fxBibTexteTrad('bib_v4_batch_pick_hint', 1); ?></p>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// v2 — options d'ordre batch (table bib_assignements + questions par épreuve)
|
||
|
||
/** MSIN-4436 — Normalise une clé de tri (ba:5, que:123 ou legacy entier). */
|
||
function fxBibNormalizeSortKey($mix) {
|
||
if ($mix === null || $mix === '' || $mix === '0' || $mix === 0) {
|
||
return '';
|
||
}
|
||
|
||
if (is_numeric($mix) && (int)$mix > 0) {
|
||
return 'ba:' . (int)$mix;
|
||
}
|
||
|
||
$str = trim((string)$mix);
|
||
if (preg_match('/^(ba|que):\d+$/', $str)) {
|
||
return $str;
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
/** MSIN-4436 — Clé de tri depuis ba_id legacy. */
|
||
function fxBibSortKeyFromBaId($int_ba_id) {
|
||
$int_ba_id = (int)$int_ba_id;
|
||
return $int_ba_id > 0 ? 'ba:' . $int_ba_id : '';
|
||
}
|
||
|
||
/** MSIN-4436 — Tris mémorisés sur l'épreuve (repli sur ba_id). */
|
||
function fxBibGetEpreuveDefaultSortKeys(array $tabEpreuve) {
|
||
$strSort1 = fxBibNormalizeSortKey($tabEpreuve['ba_bib_sort_1'] ?? '');
|
||
$strSort2 = fxBibNormalizeSortKey($tabEpreuve['ba_bib_sort_2'] ?? '');
|
||
|
||
if ($strSort1 === '') {
|
||
$strSort1 = fxBibSortKeyFromBaId((int)($tabEpreuve['ba_id'] ?? 0));
|
||
}
|
||
if ($strSort1 === '') {
|
||
$strSort1 = 'ba:2';
|
||
}
|
||
|
||
return [$strSort1, $strSort2];
|
||
}
|
||
|
||
/** MSIN-4436 — Persiste le tri batch sur l'épreuve (+ ba_id si tri fixe). */
|
||
function fxBibSaveEpreuveBatchSort($epr_id, $sort1, $sort2 = '') {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
$strSort1 = fxBibNormalizeSortKey($sort1);
|
||
$strSort2 = fxBibNormalizeSortKey($sort2);
|
||
|
||
if ($epr_id <= 0 || $strSort1 === '') {
|
||
return false;
|
||
}
|
||
|
||
if ($strSort1 === $strSort2) {
|
||
$strSort2 = '';
|
||
}
|
||
|
||
$intBaId = 0;
|
||
if (preg_match('/^ba:(\d+)$/', $strSort1, $m)) {
|
||
$intBaId = (int)$m[1];
|
||
}
|
||
|
||
$sql = "
|
||
UPDATE inscriptions_epreuves
|
||
SET ba_bib_sort_1 = '" . $objDatabase->fxEscape($strSort1) . "',
|
||
ba_bib_sort_2 = '" . $objDatabase->fxEscape($strSort2) . "'
|
||
" . ($intBaId > 0 ? ", ba_id = $intBaId" : '') . "
|
||
WHERE epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
|
||
return (bool)$objDatabase->fxQuery($sql);
|
||
}
|
||
|
||
/** MSIN-4436 — Lit sort_1 / sort_2 depuis POST (repli ba_id). */
|
||
function fxBibParseBatchSortFromPost() {
|
||
$strSort1 = fxBibNormalizeSortKey($_POST['sort_1'] ?? '');
|
||
$strSort2 = fxBibNormalizeSortKey($_POST['sort_2'] ?? '');
|
||
|
||
if ($strSort1 === '') {
|
||
$strSort1 = fxBibNormalizeSortKey($_POST['ba_id'] ?? '');
|
||
}
|
||
|
||
if ($strSort1 === '') {
|
||
$strSort1 = 'ba:2';
|
||
}
|
||
|
||
if ($strSort1 === $strSort2) {
|
||
$strSort2 = '';
|
||
}
|
||
|
||
return [$strSort1, $strSort2];
|
||
}
|
||
|
||
/** MSIN-4436 — Questions éligibles au tri pour une épreuve. */
|
||
function fxBibGetQuestionSortOptions($epr_id, $eve_id, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
$eve_id = (int)$eve_id;
|
||
if ($epr_id <= 0 || $eve_id <= 0) {
|
||
return [];
|
||
}
|
||
|
||
$strCol = ($strLangue === 'en') ? 'que_question_en' : 'que_question_fr';
|
||
$sql = "
|
||
SELECT que_id, $strCol AS que_label, que_validation
|
||
FROM inscriptions_questions
|
||
WHERE que_actif = 1
|
||
AND eve_id = $eve_id
|
||
AND (FIND_IN_SET($epr_id, que_epreuves_incluses) OR que_epreuves_incluses = '' OR que_epreuves_incluses IS NULL)
|
||
AND que_validation NOT IN ('image', 'pdf')
|
||
ORDER BY que_tri, que_id
|
||
";
|
||
$rows = $objDatabase->fxGetResults($sql);
|
||
if (!is_array($rows)) {
|
||
return [];
|
||
}
|
||
|
||
$out = [];
|
||
foreach ($rows as $row) {
|
||
$intQueId = (int)($row['que_id'] ?? 0);
|
||
if ($intQueId <= 0) {
|
||
continue;
|
||
}
|
||
$strLabel = trim((string)($row['que_label'] ?? ''));
|
||
if ($strLabel === '') {
|
||
$strLabel = 'Question #' . $intQueId;
|
||
}
|
||
if (mb_strlen($strLabel) > 72) {
|
||
$strLabel = mb_substr($strLabel, 0, 69) . '…';
|
||
}
|
||
$out[] = [
|
||
'key' => 'que:' . $intQueId,
|
||
'label' => $strLabel,
|
||
'group' => 'question',
|
||
];
|
||
}
|
||
|
||
return $out;
|
||
}
|
||
|
||
/** MSIN-4436 — Options de tri (fixes + questions) pour une épreuve. */
|
||
function fxBibGetSortOptionsForEpreuve($epr_id, $eve_id, $strLangue = 'fr', $blnTeamEpreuve = false, $blnIncludeQuestions = true) {
|
||
global $objDatabase;
|
||
|
||
$out = [];
|
||
$rows = $objDatabase->fxGetResults(
|
||
"SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri"
|
||
);
|
||
|
||
if (is_array($rows)) {
|
||
foreach ($rows as $row) {
|
||
if ((int)($row['ba_equipe'] ?? 0) === 1 && !$blnTeamEpreuve) {
|
||
continue;
|
||
}
|
||
$intBaId = (int)($row['ba_id'] ?? 0);
|
||
if ($intBaId <= 0) {
|
||
continue;
|
||
}
|
||
$strLabel = trim((string)($row['ba_nom_' . $strLangue] ?? ''));
|
||
if ($strLabel === '') {
|
||
$strLabel = trim((string)($row['ba_nom_fr'] ?? ''));
|
||
}
|
||
$out[] = [
|
||
'key' => 'ba:' . $intBaId,
|
||
'label' => $strLabel !== '' ? $strLabel : ('ba:' . $intBaId),
|
||
'group' => 'fixed',
|
||
];
|
||
}
|
||
}
|
||
|
||
if ($blnIncludeQuestions && (int)$epr_id > 0 && (int)$eve_id > 0) {
|
||
$out = array_merge($out, fxBibGetQuestionSortOptions($epr_id, $eve_id, $strLangue));
|
||
}
|
||
|
||
return $out;
|
||
}
|
||
|
||
/** MSIN-4436 — Vérifie qu'une question est liée à l'épreuve. */
|
||
function fxBibQuestionSortAllowedForEpreuve($epr_id, $que_id, $eve_id) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
$que_id = (int)$que_id;
|
||
$eve_id = (int)$eve_id;
|
||
if ($epr_id <= 0 || $que_id <= 0 || $eve_id <= 0) {
|
||
return false;
|
||
}
|
||
|
||
$sql = "
|
||
SELECT COUNT(*)
|
||
FROM inscriptions_questions
|
||
WHERE que_id = $que_id
|
||
AND eve_id = $eve_id
|
||
AND que_actif = 1
|
||
AND que_validation NOT IN ('image', 'pdf')
|
||
AND (FIND_IN_SET($epr_id, que_epreuves_incluses) OR que_epreuves_incluses = '' OR que_epreuves_incluses IS NULL)
|
||
";
|
||
|
||
return (int)$objDatabase->fxGetVar($sql) > 0;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4456 — Clause ORDER BY fiable pour « Nom d'équipe ».
|
||
* Regroupe d'abord par nom (pec / repli par_nom_equipe), puis pec_id (même nom ≠ même équipe).
|
||
*/
|
||
function fxBibTeamNameOrderClause() {
|
||
return "TRIM(IFNULL(NULLIF(c.pec_nom_equipe, ''), IFNULL(p.par_nom_equipe, ''))), p.pec_id";
|
||
}
|
||
|
||
/** MSIN-4456 — La clé de tri est-elle un critère ba_equipe (ex. Nom d'équipe) ? */
|
||
function fxBibSortKeyIsTeamCriterion($sortKey) {
|
||
global $objDatabase;
|
||
|
||
$sortKey = fxBibNormalizeSortKey($sortKey);
|
||
if (!preg_match('/^ba:(\d+)$/', $sortKey, $m)) {
|
||
return false;
|
||
}
|
||
|
||
return (int)$objDatabase->fxGetVar(
|
||
"SELECT ba_equipe FROM bib_assignements WHERE ba_id = " . (int)$m[1] . " AND ba_actif = 1 LIMIT 1"
|
||
) === 1;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4456 — Re-tri PHP des participants (filet si l'ORDER BY SQL ne regroupe pas).
|
||
* Appliqué seulement quand le tri principal est un critère équipe.
|
||
*/
|
||
function fxBibSortParticipantsByTeamName(array $participants) {
|
||
if (empty($participants)) {
|
||
return $participants;
|
||
}
|
||
|
||
$rows = [];
|
||
foreach ($participants as $row) {
|
||
$rows[] = $row;
|
||
}
|
||
|
||
usort($rows, function ($a, $b) {
|
||
$strTeamA = trim((string)($a['pec_nom_equipe'] ?? ''));
|
||
if ($strTeamA === '') {
|
||
$strTeamA = trim((string)($a['par_nom_equipe'] ?? ''));
|
||
}
|
||
$strTeamB = trim((string)($b['pec_nom_equipe'] ?? ''));
|
||
if ($strTeamB === '') {
|
||
$strTeamB = trim((string)($b['par_nom_equipe'] ?? ''));
|
||
}
|
||
|
||
$intCmp = strcasecmp($strTeamA, $strTeamB);
|
||
if ($intCmp !== 0) {
|
||
return $intCmp;
|
||
}
|
||
|
||
$intPecA = (int)($a['pec_id_original'] ?? $a['pec_id'] ?? 0);
|
||
$intPecB = (int)($b['pec_id_original'] ?? $b['pec_id'] ?? 0);
|
||
if ($intPecA !== $intPecB) {
|
||
return $intPecA <=> $intPecB;
|
||
}
|
||
|
||
$intCmp = strcasecmp((string)($a['par_nom'] ?? ''), (string)($b['par_nom'] ?? ''));
|
||
if ($intCmp !== 0) {
|
||
return $intCmp;
|
||
}
|
||
|
||
$intCmp = strcasecmp((string)($a['par_prenom'] ?? ''), (string)($b['par_prenom'] ?? ''));
|
||
if ($intCmp !== 0) {
|
||
return $intCmp;
|
||
}
|
||
|
||
return ((int)($a['par_id'] ?? 0)) <=> ((int)($b['par_id'] ?? 0));
|
||
});
|
||
|
||
$out = [];
|
||
$intCtr = 1;
|
||
foreach ($rows as $row) {
|
||
$out[$intCtr++] = $row;
|
||
}
|
||
|
||
return $out;
|
||
}
|
||
|
||
/** MSIN-4436 — Fragment ORDER BY pour une clé de tri. */
|
||
function fxBibResolveSortClause($epr_id, $sortKey, $strLangue = 'fr', $eve_id = 0) {
|
||
global $objDatabase;
|
||
|
||
$sortKey = fxBibNormalizeSortKey($sortKey);
|
||
if ($sortKey === '') {
|
||
return '';
|
||
}
|
||
|
||
if (preg_match('/^ba:(\d+)$/', $sortKey, $m)) {
|
||
$intBaId = (int)$m[1];
|
||
$tabBa = $objDatabase->fxGetRow(
|
||
"SELECT ba_sql_order, ba_equipe FROM bib_assignements WHERE ba_id = $intBaId AND ba_actif = 1 LIMIT 1"
|
||
);
|
||
if (!$tabBa) {
|
||
return '';
|
||
}
|
||
// MSIN-4456 — Ne pas se fier seul à ba_sql_order historique (souvent déjà + nom/prénom).
|
||
if ((int)($tabBa['ba_equipe'] ?? 0) === 1) {
|
||
return fxBibTeamNameOrderClause();
|
||
}
|
||
$orderBy = trim((string)($tabBa['ba_sql_order'] ?? ''));
|
||
return $orderBy !== '' ? $orderBy : '';
|
||
}
|
||
|
||
if (preg_match('/^que:(\d+)$/', $sortKey, $m)) {
|
||
$que_id = (int)$m[1];
|
||
$epr_id = (int)$epr_id;
|
||
if ($epr_id <= 0) {
|
||
return '';
|
||
}
|
||
if ($eve_id <= 0) {
|
||
$eve_id = (int)$objDatabase->fxGetVar(
|
||
"SELECT eve_id FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1"
|
||
);
|
||
}
|
||
if (!fxBibQuestionSortAllowedForEpreuve($epr_id, $que_id, $eve_id)) {
|
||
return '';
|
||
}
|
||
$strCol = ($strLangue === 'en') ? 'que_choix_en' : 'que_choix_fr';
|
||
return "(
|
||
SELECT TRIM(rq.$strCol)
|
||
FROM resultats_questions rq
|
||
WHERE rq.que_actif = 1
|
||
AND rq.que_id = $que_id
|
||
AND rq.par_id = p.par_id
|
||
AND rq.pec_id = p.pec_id
|
||
LIMIT 1
|
||
)";
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
/** MSIN-4436 — ORDER BY complet (2 niveaux + tie-breaker). */
|
||
function fxBibBuildBatchOrderBy($epr_id, $sort1, $sort2 = '', $strLangue = 'fr', $eve_id = 0) {
|
||
$epr_id = (int)$epr_id;
|
||
if ($eve_id <= 0 && $epr_id > 0) {
|
||
global $objDatabase;
|
||
$eve_id = (int)$objDatabase->fxGetVar(
|
||
"SELECT eve_id FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1"
|
||
);
|
||
}
|
||
|
||
$strSort1 = fxBibNormalizeSortKey($sort1);
|
||
$strSort2 = fxBibNormalizeSortKey($sort2);
|
||
if ($strSort1 === $strSort2) {
|
||
$strSort2 = '';
|
||
}
|
||
|
||
$tabParts = [];
|
||
foreach ([$strSort1, $strSort2] as $mixKey) {
|
||
if ($mixKey === '') {
|
||
continue;
|
||
}
|
||
$strClause = fxBibResolveSortClause($epr_id, $mixKey, $strLangue, $eve_id);
|
||
// MSIN-4456 — Tri principal « nom d'équipe » + secondaire alphabétique :
|
||
// la clause équipe ne doit PAS déjà embarquer par_nom (sinon le 2e niveau est noyé).
|
||
if ($mixKey === $strSort1 && fxBibSortKeyIsTeamCriterion($mixKey) && $strSort2 !== '') {
|
||
$strClause = fxBibTeamNameOrderClause();
|
||
}
|
||
if ($strClause !== '' && !in_array($strClause, $tabParts, true)) {
|
||
$tabParts[] = $strClause;
|
||
}
|
||
}
|
||
|
||
if (empty($tabParts)) {
|
||
$tabParts[] = 'p.par_nom, p.par_prenom';
|
||
}
|
||
|
||
$tabParts[] = 'p.par_id ASC';
|
||
|
||
return implode(', ', $tabParts);
|
||
}
|
||
|
||
/** MSIN-4436 — Rendu des <option> pour un select de tri. */
|
||
function fxBibRenderBatchSortOptions($tabOptions, $strSelected, $blnAllowEmpty = false, $strLangue = 'fr') {
|
||
$strSelected = fxBibNormalizeSortKey($strSelected);
|
||
$html = '';
|
||
|
||
if ($blnAllowEmpty) {
|
||
$strNone = fxBibTexte('bib_v4_batch_order_none', 0);
|
||
$html .= '<option value=""' . ($strSelected === '' ? ' selected' : '') . '>'
|
||
. fxBibEsc($strNone) . '</option>';
|
||
}
|
||
|
||
$tabFixed = [];
|
||
$tabQuestions = [];
|
||
foreach ($tabOptions as $opt) {
|
||
if (($opt['group'] ?? '') === 'question') {
|
||
$tabQuestions[] = $opt;
|
||
} else {
|
||
$tabFixed[] = $opt;
|
||
}
|
||
}
|
||
|
||
if (!empty($tabFixed)) {
|
||
$html .= '<optgroup label="' . fxBibEsc(fxBibTexte('bib_v4_batch_sort_group_fixed', 0)) . '">';
|
||
foreach ($tabFixed as $opt) {
|
||
$strKey = fxBibEsc($opt['key'] ?? '');
|
||
$html .= '<option value="' . $strKey . '"'
|
||
. ($strSelected === ($opt['key'] ?? '') ? ' selected' : '') . '>'
|
||
. fxBibEsc($opt['label'] ?? '') . '</option>';
|
||
}
|
||
$html .= '</optgroup>';
|
||
}
|
||
|
||
if (!empty($tabQuestions)) {
|
||
$html .= '<optgroup label="' . fxBibEsc(fxBibTexte('bib_v4_batch_sort_group_questions', 0)) . '">';
|
||
foreach ($tabQuestions as $opt) {
|
||
$strKey = fxBibEsc($opt['key'] ?? '');
|
||
$html .= '<option value="' . $strKey . '"'
|
||
. ($strSelected === ($opt['key'] ?? '') ? ' selected' : '') . '>'
|
||
. fxBibEsc($opt['label'] ?? '') . '</option>';
|
||
}
|
||
$html .= '</optgroup>';
|
||
}
|
||
|
||
return $html;
|
||
}
|
||
|
||
// v2 — options d'ordre batch (table bib_assignements)
|
||
function renderBatchConfig($epr_id, $eve_id, $strLangue = 'fr', $isTeamEpreuve = false, $strSort1 = '', $strSort2 = '') {
|
||
$epr_id = (int)$epr_id;
|
||
$eve_id = (int)$eve_id;
|
||
$strSort1 = fxBibNormalizeSortKey($strSort1);
|
||
$strSort2 = fxBibNormalizeSortKey($strSort2);
|
||
if ($strSort1 === '') {
|
||
$strSort1 = 'ba:2';
|
||
}
|
||
|
||
$tabOptions = fxBibGetSortOptionsForEpreuve($epr_id, $eve_id, $strLangue, $isTeamEpreuve, true);
|
||
|
||
ob_start();
|
||
?>
|
||
|
||
<div class="batch-config">
|
||
|
||
<div class="batch-config-ready bib-ui-hidden">
|
||
|
||
<div class="mb-2 epr-batch-order-wrap">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order', 1); ?></label>
|
||
<select class="form-control form-control-sm batch-order">
|
||
<?php echo fxBibRenderBatchSortOptions($tabOptions, $strSort1, false, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="mb-2 epr-batch-order-wrap epr-batch-order-wrap--secondary">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order_2', 1); ?></label>
|
||
<select class="form-control form-control-sm batch-order-2">
|
||
<?php echo fxBibRenderBatchSortOptions($tabOptions, $strSort2, true, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- OPTION -->
|
||
<div class="mb-2">
|
||
<?php /* OPTION LAST TEMPORAIREMENT DÉSACTIVÉE
|
||
<label>
|
||
<input type="checkbox" class="batch-last">
|
||
Commencer à partir de la dernière assignation
|
||
</label>
|
||
*/ ?>
|
||
</div>
|
||
|
||
<!-- ANALYSE -->
|
||
<p class="batch-reset-warning text-danger small mb-2 bib-ui-hidden"><?php fxBibTexte('bib_v4_js_reset_warning', 1); ?></p>
|
||
<?php echo fxBibActionGroupOpen('epr-batch-info-group text-muted small'); ?>
|
||
<span class="batch-info-text"></span>
|
||
<?php echo fxBibAideButton('bib_v4_batch_info', '', false); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<?php
|
||
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// ============================================================
|
||
// MSIN-4379 — Refonte UI assignation dossards v4 (fxShowBibTool4)
|
||
// Layout 2 colonnes, Tippy.js, clés info / info_aide, en-tête séquences via AJAX.
|
||
// Bloc gestion épreuve : .epr-block-gestion (quantités / paramètres).
|
||
// ============================================================
|
||
|
||
/**
|
||
* URL de retour promoteur selon ?from= (whitelist).
|
||
* $strDefault si from absent — ex. liste_attente : epreuves, gestion_epreuves : promoteur.
|
||
* MSIN-4399 — from=promoteur → hub V2 + focus événement si le hub est disponible.
|
||
*/
|
||
function fxGetPromoteurBackUrl($intEveId, $strPage = '/compte', $strDefault = 'promoteur') {
|
||
global $vDomaine;
|
||
|
||
$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;
|
||
}
|
||
|
||
if ($strFrom === 'promoteur') {
|
||
if (!function_exists('fxPromoteurHubOrLegacyBackUrl')) {
|
||
require_once __DIR__ . '/inc_fx_promoteur_hub.php';
|
||
}
|
||
$strLangue = ($strPage === '/account') ? 'en' : 'fr';
|
||
|
||
return fxPromoteurHubOrLegacyBackUrl($intEveId, $strLangue);
|
||
}
|
||
|
||
$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']);
|
||
}
|
||
|
||
/** MSIN-4436 — Au moins une séquence verrouillée sur l'épreuve. */
|
||
function fxBibEpreuveHasLockedRanges($epr_id) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
|
||
if ($epr_id <= 0) {
|
||
return false;
|
||
}
|
||
|
||
$sql = "
|
||
SELECT COUNT(*)
|
||
FROM inscriptions_epreuves_bib
|
||
WHERE epr_id = $epr_id
|
||
AND epr_bib_locked = 1
|
||
";
|
||
|
||
return (int)$objDatabase->fxGetVar($sql) > 0;
|
||
}
|
||
|
||
/** MSIN-4436 — Réinitialisation totale : aucun cadenas sur l'épreuve. */
|
||
function fxBibAssertEpreuveNoLockedRanges($epr_id) {
|
||
if (fxBibEpreuveHasLockedRanges($epr_id)) {
|
||
return ['success' => false, 'message' => fxBibMsg('bib_v4_js_reset_all_locked')];
|
||
}
|
||
|
||
return ['success' => true];
|
||
}
|
||
|
||
/** MSIN-4424 — Mêmes numéros de dossard autorisés entre épreuves (réglage événement). */
|
||
function fxBibEventAllowsInterEprDuplicates($int_eve_id) {
|
||
global $objDatabase;
|
||
|
||
static $memCache = [];
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
|
||
if ($int_eve_id <= 0) {
|
||
return false;
|
||
}
|
||
|
||
if (array_key_exists($int_eve_id, $memCache)) {
|
||
return $memCache[$int_eve_id];
|
||
}
|
||
|
||
$intVal = (int)$objDatabase->fxGetVar(
|
||
'SELECT eve_bib_allow_inter_epr FROM inscriptions_evenements WHERE eve_id = ' . $int_eve_id . ' LIMIT 1'
|
||
);
|
||
|
||
$memCache[$int_eve_id] = ($intVal === 1);
|
||
|
||
return $memCache[$int_eve_id];
|
||
}
|
||
|
||
/** MSIN-4424 — Persiste le réglage doublons inter-épreuves. */
|
||
function fxBibSetEventAllowsInterEprDuplicates($int_eve_id, $blnAllow) {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$intAllow = $blnAllow ? 1 : 0;
|
||
|
||
if ($int_eve_id <= 0) {
|
||
return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')];
|
||
}
|
||
|
||
$objDatabase->fxQuery(
|
||
'UPDATE inscriptions_evenements SET eve_bib_allow_inter_epr = ' . $intAllow
|
||
. ' WHERE eve_id = ' . $int_eve_id . ' LIMIT 1'
|
||
);
|
||
|
||
return ['success' => true, 'allow_inter_epr' => ($intAllow === 1)];
|
||
}
|
||
|
||
/** Resout eve_id depuis la requete AJAX bib (eve_id, epr_id ou epr_bib_id / id). */
|
||
function fxBibResolveEveIdFromRequest() {
|
||
global $objDatabase;
|
||
|
||
if (!empty($_REQUEST['eve_id'])) {
|
||
return intval($_REQUEST['eve_id']);
|
||
}
|
||
|
||
$intEprId = intval($_REQUEST['epr_id'] ?? 0);
|
||
if ($intEprId > 0) {
|
||
$intEveId = intval($objDatabase->fxGetVar(
|
||
'SELECT eve_id FROM inscriptions_epreuves WHERE epr_id = ' . $intEprId . ' LIMIT 1'
|
||
));
|
||
|
||
return ($intEveId > 0) ? $intEveId : 0;
|
||
}
|
||
|
||
// delete n'envoyait que id (epr_bib_id) — seule action sans epr_id ni eve_id
|
||
$intBibId = intval($_REQUEST['epr_bib_id'] ?? $_REQUEST['id'] ?? 0);
|
||
if ($intBibId <= 0) {
|
||
return 0;
|
||
}
|
||
|
||
$intEveId = intval($objDatabase->fxGetVar(
|
||
'SELECT e.eve_id FROM inscriptions_epreuves_bib b '
|
||
. 'INNER JOIN inscriptions_epreuves e ON e.epr_id = b.epr_id '
|
||
. 'WHERE b.epr_bib_id = ' . $intBibId . ' LIMIT 1'
|
||
));
|
||
|
||
return ($intEveId > 0) ? $intEveId : 0;
|
||
}
|
||
|
||
/** Gate AJAX bib v4 — session promoteur + CSRF (pas de granularite v2 pour l'instant). */
|
||
function fxBibRequireAjaxAccess() {
|
||
if (!fxBibRequirePromoteurSession()) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_session_invalid'),
|
||
]);
|
||
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_anomalies_orphan_annule' => ['fr' => 'Annulée — dossard encore en séquence', 'en' => 'Cancelled — bib still in sequence'],
|
||
'bib_v4_anomalies_orphan_transfert'=> ['fr' => 'Transférée — dossard conservé', 'en' => 'Transferred — bib kept'],
|
||
'bib_v4_anomalies_view_inscription'=> ['fr' => "Voir l'inscription", 'en' => 'View registration'],
|
||
'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_global_batch_existing_title' => ['fr' => 'Assignation des dossards avec séquences existantes', 'en' => 'Bib assignment with existing sequences'],
|
||
'bib_v4_global_batch_generated_title' => ['fr' => 'Assignation de dossards sans séquence existante', 'en' => 'Bib assignment without existing sequences'],
|
||
'bib_v4_global_batch_start_bib' => ['fr' => 'Dossard numéro 1', 'en' => 'First bib number'],
|
||
'bib_v4_global_batch_gen_hint' => ['fr' => 'Épreuves solo sans séquence : une plage est créée pour chaque épreuve sélectionnée, à la taille exacte des inscriptions à assigner. Les numéros se suivent dans l\'ordre des épreuves.', 'en' => 'Solo races without sequences: one range is created per selected race, sized exactly to registrations to assign. Bib numbers continue in race order.'],
|
||
'bib_v4_global_batch_gen_range_preview' => ['fr' => 'Plage prévue : %d → %d · %d à assigner', 'en' => 'Planned range: %d → %d · %d to assign'],
|
||
'bib_v4_global_batch_gen_plan_invalid' => ['fr' => 'Sélection invalide : dossard de départ et au moins une épreuve avec inscriptions à assigner.', 'en' => 'Invalid selection: starting bib and at least one race with registrations to assign.'],
|
||
'bib_v4_global_batch_gen_no_pending' => ['fr' => 'Aucune inscription à assigner dans les épreuves sélectionnées.', 'en' => 'No registrations to assign in the selected races.'],
|
||
'bib_v4_global_batch_gen_has_seq' => ['fr' => 'Une épreuve sélectionnée a déjà une séquence — rechargez le panneau.', 'en' => 'A selected race already has a sequence — reload the panel.'],
|
||
'bib_v4_global_batch_gen_no_start' => ['fr' => 'Indiquez le numéro du premier dossard.', 'en' => 'Enter the first bib number.'],
|
||
'bib_v4_global_batch_gen_insert_failed' => ['fr' => 'Impossible de créer la séquence de dossards. Réessayez ou rechargez la page.', 'en' => 'Could not create the bib sequence. Try again or reload the page.'],
|
||
'bib_v4_js_global_gen_epr_missing' => ['fr' => 'Épreuve introuvable sur la page après création des séquences. Rechargez la page puis réessayez.', 'en' => 'Race not found on the page after creating sequences. Reload the page and try again.'],
|
||
'bib_v4_ajax_error' => ['fr' => 'Erreur', 'en' => 'Error'],
|
||
'bib_v4_global_batch_unavailable' => ['fr' => 'Aucune assignation globale disponible pour cet événement.', 'en' => 'No global assignment available for this event.'],
|
||
'bib_v4_ajax_global_gen_sim_summary' => ['fr' => '%d épreuve(s) · %d dossards · %d à assigner', 'en' => '%d race(s) · %d bibs · %d to assign'],
|
||
'bib_v4_ajax_global_gen_analysis' => ['fr' => '%d épreuve(s) · plage %d → %d · %d à assigner', 'en' => '%d race(s) · range %d → %d · %d to assign'],
|
||
'bib_v4_js_global_batch_finalizing' => ['fr' => 'Finalisation — mise à jour de l\'affichage…', 'en' => 'Finishing — refreshing the display…'],
|
||
'bib_v4_global_batch_go_complete_title' => ['fr' => 'Assignation terminée', 'en' => 'Assignment complete'],
|
||
'bib_v4_global_batch_go_complete_summary' => ['fr' => '%d dossard(s) assigné(s) sur %d · %d épreuve(s)', 'en' => '%d bib(s) assigned of %d · %d race(s)'],
|
||
'bib_v4_global_batch_go_complete_reload' => ['fr' => 'OK — Recharger la page', 'en' => 'OK — Reload page'],
|
||
// MSIN-4445 — Assignation libre.
|
||
'bib_v4_global_batch_free_title' => ['fr' => 'Assignation libre', 'en' => 'Free assignment'],
|
||
'bib_v4_global_batch_free_hint' => ['fr' => 'Toutes les épreuves solo : choisissez Début et Fin (ou Qté). Les dossards sont assignés sans créer de séquence, même si une séquence existe déjà. Le Go reste disponible même si la quantité n\'est pas juste.', 'en' => 'All solo races: choose Start and End (or Qty). Bibs are assigned without creating a sequence, even if a sequence already exists. Go stays available even if the quantity is not exact.'],
|
||
'bib_v4_global_batch_free_qty_juste' => ['fr' => 'Quantité juste', 'en' => 'Exact quantity'],
|
||
'bib_v4_global_batch_free_qty_manquante' => ['fr' => 'Quantité manquante : %d', 'en' => 'Missing quantity: %d'],
|
||
'bib_v4_global_batch_free_qty_supplementaire' => ['fr' => 'Quantité supplémentaire : %d', 'en' => 'Extra quantity: %d'],
|
||
'bib_v4_global_batch_free_dupes_warn' => ['fr' => 'Attention : vous êtes en train de créer des inscriptions avec des dossards en double.', 'en' => 'Warning: you are about to create registrations with duplicate bib numbers.'],
|
||
'bib_v4_global_batch_free_plan_invalid' => ['fr' => 'Sélection invalide : Début, Fin (ou Qté) et au moins une épreuve avec inscriptions à assigner.', 'en' => 'Invalid selection: Start, End (or Qty) and at least one race with registrations to assign.'],
|
||
'bib_v4_ajax_global_free_analysis' => ['fr' => '%d épreuve(s) · plage %d → %d · %d à assigner · %s', 'en' => '%d race(s) · range %d → %d · %d to assign · %s'],
|
||
'bib_v4_ajax_global_free_sim_summary' => ['fr' => '%d épreuve(s) · %d dossards · %d à assigner · %s', 'en' => '%d race(s) · %d bibs · %d to assign · %s'],
|
||
'bib_v4_batch_order_2' => ['fr' => 'Tri secondaire', 'en' => 'Secondary sort'],
|
||
'bib_v4_batch_order_none' => ['fr' => '— Aucun —', 'en' => '— None —'],
|
||
'bib_v4_batch_sort_group_fixed' => ['fr' => 'Critères fixes', 'en' => 'Fixed criteria'],
|
||
'bib_v4_summary_teams_unit' => ['fr' => 'équipes', 'en' => 'teams'],
|
||
// MSIN-4467 — Nouvelle architecture visuelle du module.
|
||
'bib_v5_workspace_label' => ['fr' => 'Gestion des dossards', 'en' => 'Bib management'],
|
||
'bib_v5_workspace_preparation' => ['fr' => 'Préparation', 'en' => 'Preparation'],
|
||
'bib_v5_workspace_production' => ['fr' => 'Production de dossards', 'en' => 'Bib production'],
|
||
'bib_v5_workspace_operations' => ['fr' => 'Opérations', 'en' => 'Operations'],
|
||
'bib_v5_workspace_settings' => ['fr' => 'Réglages', 'en' => 'Settings'],
|
||
'bib_v5_preparation_intro' => ['fr' => 'Préparez les épreuves et attribuez les dossards aux inscriptions.', 'en' => 'Prepare races and assign bibs to registrations.'],
|
||
'bib_v5_group_quantities' => ['fr' => 'Quantités', 'en' => 'Quantities'],
|
||
'bib_v5_group_bibs' => ['fr' => 'Dossards', 'en' => 'Bibs'],
|
||
'bib_v5_modes_intro' => ['fr' => 'Utilisez les modes d’assignation qui traitent plusieurs épreuves ou des besoins particuliers.', 'en' => 'Use assignment modes that process multiple races or special requirements.'],
|
||
'bib_v5_stat_races' => ['fr' => 'Épreuves actives', 'en' => 'Active races'],
|
||
'bib_v5_stat_registered' => ['fr' => 'Inscriptions', 'en' => 'Registrations'],
|
||
'bib_v5_stat_assigned' => ['fr' => 'Dossards attribués', 'en' => 'Assigned bibs'],
|
||
'bib_v5_stat_pending' => ['fr' => 'À attribuer', 'en' => 'To assign'],
|
||
'bib_v5_race_ready' => ['fr' => 'Prête', 'en' => 'Ready'],
|
||
'bib_v5_race_incomplete' => ['fr' => 'À compléter', 'en' => 'To complete'],
|
||
'bib_v5_quantities_title' => ['fr' => 'Quantités d’inscription', 'en' => 'Registration quantities'],
|
||
'bib_v5_bib_assignment_title' => ['fr' => 'Attribution des dossards', 'en' => 'Bib assignment'],
|
||
'bib_v5_ranges_title' => ['fr' => 'Plages de numéros', 'en' => 'Number ranges'],
|
||
'bib_v5_ranges_hint' => ['fr' => 'Définissez les numéros disponibles pour cette épreuve.', 'en' => 'Define the numbers available for this race.'],
|
||
'bib_v5_method_title' => ['fr' => 'Méthode d’attribution', 'en' => 'Assignment method'],
|
||
// MSIN-4468 — Filet de secours; la source officielle demeure la table info.
|
||
'bib_v5_qte_total_min' => [
|
||
'fr' => 'Quantité refusée : le total doit être d’au moins %d, soit le nombre d’inscriptions déjà vendues.',
|
||
'en' => 'Quantity rejected: the total must be at least %d, which is the number of registrations already sold.',
|
||
],
|
||
'bib_v5_batch_title' => ['fr' => 'Attribuer maintenant', 'en' => 'Assign now'],
|
||
'bib_v5_batch_hint' => ['fr' => 'Attribuer en lot aux inscriptions qui n’ont pas encore de dossard.', 'en' => 'Assign in bulk to registrations that do not have a bib yet.'],
|
||
'bib_v5_auto_title' => ['fr' => 'Nouvelles inscriptions', 'en' => 'New registrations'],
|
||
'bib_v5_auto_hint' => ['fr' => 'Attribuer automatiquement un dossard lors des prochaines inscriptions.', 'en' => 'Automatically assign a bib to future registrations.'],
|
||
'bib_v5_advanced_actions' => ['fr' => 'Actions avancées', 'en' => 'Advanced actions'],
|
||
'bib_v5_production_intro' => ['fr' => 'Préparez les informations nécessaires à l’impression des dossards à partir des plages déjà configurées.', 'en' => 'Prepare the information required to print bibs using the ranges already configured.'],
|
||
'bib_v5_production_planned' => ['fr' => 'Fonctionnalité prévue — aucune donnée ne sera enregistrée pour le moment.', 'en' => 'Planned feature — no data will be saved yet.'],
|
||
'bib_v5_production_step_ranges' => ['fr' => 'Choisir les plages', 'en' => 'Choose ranges'],
|
||
'bib_v5_production_step_answers' => ['fr' => 'Répondre par catégorie', 'en' => 'Answer by category'],
|
||
'bib_v5_production_step_review' => ['fr' => 'Réviser la production', 'en' => 'Review production'],
|
||
'bib_v5_production_step_printer' => ['fr' => 'Transmettre à l’imprimeur', 'en' => 'Send to printer'],
|
||
'bib_v5_production_categories' => ['fr' => 'Préparation par épreuve et catégorie', 'en' => 'Preparation by race and category'],
|
||
'bib_v5_production_ranges' => ['fr' => 'Plages existantes', 'en' => 'Existing ranges'],
|
||
'bib_v5_production_color' => ['fr' => 'Couleur du dossard', 'en' => 'Bib colour'],
|
||
'bib_v5_production_questions' => ['fr' => 'Questions de production', 'en' => 'Production questions'],
|
||
'bib_v5_production_to_define' => ['fr' => 'À définir', 'en' => 'To be defined'],
|
||
'bib_v5_production_status' => ['fr' => 'À préparer', 'en' => 'To prepare'],
|
||
// MSIN-4469 — Filet de secours; la source officielle demeure la table info.
|
||
'bib_v5_production_excel_title' => ['fr' => 'Fichier Excel pour l’imprimeur', 'en' => 'Printer Excel file'],
|
||
'bib_v5_production_excel_intro' => ['fr' => 'Le fichier contient un onglet Imprimeur et un onglet Commande MS1.', 'en' => 'The file contains a Printer sheet and an MS1 Order sheet.'],
|
||
'bib_v5_production_excel_generate' => ['fr' => 'Générer et verrouiller', 'en' => 'Generate and lock'],
|
||
'bib_v5_production_excel_generate_help' => ['fr' => 'Cette action crée le fichier officiel et verrouille les séquences pour l’impression.', 'en' => 'This creates the official file and locks the ranges for printing.'],
|
||
'bib_v5_production_excel_download' => ['fr' => 'Télécharger de nouveau', 'en' => 'Download again'],
|
||
'bib_v5_production_excel_locked' => ['fr' => 'En impression — séquences verrouillées', 'en' => 'In print — ranges locked'],
|
||
'bib_v5_production_excel_meta' => ['fr' => 'Version %d créée le %s par %s', 'en' => 'Version %d created on %s by %s'],
|
||
'bib_v5_production_excel_generating' => ['fr' => 'Génération en cours — rechargez la page dans quelques instants.', 'en' => 'Generation in progress — reload the page shortly.'],
|
||
'bib_v5_production_no_ranges' => ['fr' => 'Aucune séquence de dossards à produire.', 'en' => 'No bib ranges to produce.'],
|
||
'bib_v5_production_event_invalid' => ['fr' => 'Événement introuvable.', 'en' => 'Event not found.'],
|
||
'bib_v5_production_range_invalid' => ['fr' => 'Une séquence de dossards est invalide.', 'en' => 'A bib range is invalid.'],
|
||
'bib_v5_production_generation_error' => ['fr' => 'Impossible de générer le fichier Excel.', 'en' => 'Unable to generate the Excel file.'],
|
||
'bib_v5_production_file_missing' => ['fr' => 'Le fichier Excel enregistré est introuvable.', 'en' => 'The saved Excel file could not be found.'],
|
||
'bib_v5_production_col_bib' => ['fr' => 'Numéro de dossard', 'en' => 'Bib number'],
|
||
'bib_v5_production_col_race' => ['fr' => 'Épreuve', 'en' => 'Race'],
|
||
'bib_v5_production_col_printer_lines' => ['fr' => 'Lignes Imprimeur', 'en' => 'Printer lines'],
|
||
'bib_v5_production_total' => ['fr' => 'TOTAL', 'en' => 'TOTAL'],
|
||
'bib_v5_production_locked_error' => ['fr' => 'Les séquences sont verrouillées parce que le fichier est en impression.', 'en' => 'The ranges are locked because the file is in print.'],
|
||
'bib_v5_production_print_lock_col' => ['fr' => 'Impression', 'en' => 'Printing'],
|
||
'bib_v5_production_print_lock_tip' => ['fr' => 'Verrouillé pour l’impression : cette séquence ne peut plus être modifiée.', 'en' => 'Locked for printing: this range can no longer be modified.'],
|
||
'bib_v5_production_dev_unlock' => ['fr' => 'Déverrouiller pour le développement', 'en' => 'Unlock for development'],
|
||
'bib_v5_production_dev_unlock_help' => ['fr' => 'Réactive temporairement la modification de toutes les séquences de cet événement.', 'en' => 'Temporarily enables editing for all ranges in this event.'],
|
||
'bib_v5_operations_intro' => ['fr' => 'Contrôlez les anomalies et préparez les documents pour la distribution.', 'en' => 'Review anomalies and prepare distribution documents.'],
|
||
'bib_v5_settings_intro' => ['fr' => 'Gérez les règles qui s’appliquent à l’ensemble de l’événement.', 'en' => 'Manage rules that apply to the entire event.'],
|
||
'bib_v4_event_config_title' => ['fr' => "Configuration globale pour l'assignation de dossard", 'en' => 'Global bib assignment settings'],
|
||
'bib_v4_event_config_inter_epr_on' => ['fr' => 'Inter épreuve', 'en' => 'Inter-race'],
|
||
'bib_v4_anomalies_nav_todo' => ['fr' => 'Élément à valider', 'en' => 'Item to review'],
|
||
'bib_v4_anomalies_nav_todo_fmt' => ['fr' => 'Élément à valider : %d', 'en' => 'Item to review: %d'],
|
||
'bib_v4_qty_summary_title' => ['fr' => 'Sommaire des quantités', 'en' => 'Quantity summary'],
|
||
'bib_v4_qty_summary_a_assigner' => ['fr' => 'À assigner', 'en' => 'To assign'],
|
||
'bib_v4_qty_summary_bib_restant' => ['fr' => 'Dossards restants', 'en' => 'Bibs remaining'],
|
||
'bib_v4_qty_summary_orphelins' => ['fr' => 'Personnes orphelines', 'en' => 'Orphan participants'],
|
||
'bib_v4_qty_summary_total' => ['fr' => 'Inscrits', 'en' => 'Registered'],
|
||
'bib_v4_qty_summary_avec_bib' => ['fr' => 'Avec dossard', 'en' => 'With bib'],
|
||
'bib_v4_qty_summary_sans_bib' => ['fr' => 'Sans dossard', 'en' => 'Without bib'],
|
||
'bib_v4_qty_summary_places_dispo' => ['fr' => 'Places disponibles', 'en' => 'Places available'],
|
||
'bib_v4_qty_summary_global' => ['fr' => 'Total événement', 'en' => 'Event total'],
|
||
'bib_v4_qty_summary_by_epr' => ['fr' => 'Détail par épreuve', 'en' => 'Breakdown by race'],
|
||
'bib_v4_qty_summary_col_epr' => ['fr' => 'Épreuve', 'en' => 'Race'],
|
||
'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)'],
|
||
'bib_v4_dist_print_title' => ['fr' => 'Impression PDF — distribution des dossards', 'en' => 'PDF print — bib distribution'],
|
||
'bib_v4_dist_print_questions' => ['fr' => 'Colonnes optionnelles (questions)', 'en' => 'Optional columns (questions)'],
|
||
'bib_v4_dist_print_generate' => ['fr' => 'Générer le PDF', 'en' => 'Generate PDF'],
|
||
'bib_v4_dist_print_last_none' => ['fr' => 'Aucune impression enregistrée pour cet événement.', 'en' => 'No print recorded for this event yet.'],
|
||
'bib_v4_dist_print_max_questions' => ['fr' => 'Maximum %d questions par épreuve pour le format lettre.', 'en' => 'Maximum %d questions per race for letter format.'],
|
||
'bib_v4_dist_print_no_questions' => ['fr' => 'Aucune question éligible pour cette épreuve.', 'en' => 'No eligible question for this race.'],
|
||
'bib_v4_dist_print_col_bib' => ['fr' => 'Dossard', 'en' => 'Bib'],
|
||
'bib_v4_dist_print_col_nom' => ['fr' => 'Nom', 'en' => 'Last name'],
|
||
'bib_v4_dist_print_col_prenom' => ['fr' => 'Prénom', 'en' => 'First name'],
|
||
// MSIN-4471 — Feuille bénévole : nom+prénom + case remise.
|
||
'bib_v4_dist_print_col_nom_prenom' => ['fr' => 'Nom, Prénom', 'en' => 'Last name, First name'],
|
||
'bib_v4_dist_print_col_check' => ['fr' => 'OK', 'en' => 'OK'],
|
||
'bib_v4_dist_print_col_sexe' => ['fr' => 'Sexe', 'en' => 'Gender'],
|
||
'bib_v4_dist_print_empty_epr' => ['fr' => 'Aucun dossard assigné pour cette épreuve.', 'en' => 'No bib assigned for this race.'],
|
||
'bib_v4_dist_print_last' => ['fr' => 'Dernière impression : %s — %s', 'en' => 'Last print: %s — %s'],
|
||
'bib_v4_dist_print_footer' => ['fr' => 'Imprimé le %s — %s', 'en' => 'Printed on %s — %s'],
|
||
'bib_v4_dist_print_page' => ['fr' => 'Page %s / %s', 'en' => 'Page %s / %s'],
|
||
];
|
||
|
||
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;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4424 — Séquences qui chevauchent [start, end].
|
||
* Par défaut : tout l'événement. Si doublons inter-épreuves autorisés : même epr_id seulement.
|
||
*
|
||
* @return array|null Tableau 1-based fxGetResults, ou null si paramètres invalides.
|
||
*/
|
||
function fxBibGetOverlappingRanges($eve_id, $start, $end, $exclude_bib_id = 0, $epr_id = 0) {
|
||
global $objDatabase;
|
||
|
||
$eve_id = (int)$eve_id;
|
||
$start = (int)$start;
|
||
$end = (int)$end;
|
||
$exclude_bib_id = (int)$exclude_bib_id;
|
||
$epr_id = (int)$epr_id;
|
||
|
||
if ($eve_id <= 0 || $start <= 0 || $end <= 0) {
|
||
return null;
|
||
}
|
||
|
||
$sqlExclude = ($exclude_bib_id > 0) ? "AND b.epr_bib_id <> $exclude_bib_id" : '';
|
||
$sqlEprOnly = '';
|
||
|
||
if ($epr_id > 0 && fxBibEventAllowsInterEprDuplicates($eve_id)) {
|
||
$sqlEprOnly = "AND b.epr_id = $epr_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
|
||
$sqlEprOnly
|
||
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',
|
||
'qte-total-min' => 'bib_v5_qte_total_min',
|
||
'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',
|
||
'global-gen-no-start' => 'bib_v4_global_batch_gen_no_start',
|
||
'global-gen-epr-missing' => 'bib_v4_js_global_gen_epr_missing',
|
||
'global-gen-no-epr' => 'bib_v4_js_global_no_epr',
|
||
'global-batch-finalizing' => 'bib_v4_js_global_batch_finalizing',
|
||
'global-batch-complete-title' => 'bib_v4_global_batch_go_complete_title',
|
||
'global-batch-complete-summary' => 'bib_v4_global_batch_go_complete_summary',
|
||
'global-batch-complete-reload' => 'bib_v4_global_batch_go_complete_reload',
|
||
// MSIN-4445
|
||
'global-free-qty-juste' => 'bib_v4_global_batch_free_qty_juste',
|
||
'global-free-qty-manquante' => 'bib_v4_global_batch_free_qty_manquante',
|
||
'global-free-qty-supplementaire' => 'bib_v4_global_batch_free_qty_supplementaire',
|
||
'global-free-dupes-warn' => 'bib_v4_global_batch_free_dupes_warn',
|
||
'global-free-plan-invalid' => 'bib_v4_global_batch_free_plan_invalid',
|
||
'reset-all-confirm' => 'bib_v4_js_reset_all_confirm',
|
||
'reset-all-locked' => 'bib_v4_js_reset_all_locked',
|
||
'assign-full' => 'bib_v4_ajax_assign_full',
|
||
'assign-partial' => 'bib_v4_ajax_assign_partial',
|
||
'assign-none' => 'bib_v4_ajax_assign_none',
|
||
'anomalies-nav-todo' => 'bib_v4_anomalies_nav_todo',
|
||
'anomalies-nav-todo-fmt' => 'bib_v4_anomalies_nav_todo_fmt',
|
||
];
|
||
$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) . '"';
|
||
}
|
||
|
||
/** Bouton œil (grille dossards) + crayon traduction en mode Textes — clé bib_v4_col_view. */
|
||
function fxBibRenderViewRangeButton($intEprId, $intRangeId, $strBtnClass = 'btn btn-sm btn-secondary btn-view-range') {
|
||
return '<span class="bib-view-range-cell">'
|
||
. '<button type="button"'
|
||
. ' class="' . fxBibEsc($strBtnClass) . '"'
|
||
. ' data-epr-id="' . (int)$intEprId . '"'
|
||
. ' data-range-id="' . (int)$intRangeId . '"'
|
||
. fxBibAideTippyAttr('bib_v4_col_view') . '>'
|
||
. '<i class="fa fa-eye" aria-hidden="true"></i>'
|
||
. '</button>'
|
||
. fxBibTradButton('bib_v4_col_view')
|
||
. '</span>';
|
||
}
|
||
|
||
/** 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 '<span class="bib-aide-text" hidden>' . fxBibEsc($strAide) . '</span>?';
|
||
}
|
||
|
||
/** 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 = '<button type="button" class="' . fxBibEsc($strClass) . '" aria-label="' . fxBibEsc(fxBibTexte('bib_v4_aide_label', 0)) . '">'
|
||
. $strInner
|
||
. '</button>';
|
||
}
|
||
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 = '<span class="epr-header-label">' . fxBibEsc(fxBibTexte($clef, 0)) . fxBibAideButton($clef);
|
||
if ($docAnchorClef !== '') {
|
||
$html .= fxDocRenderTrigger($docAnchorClef);
|
||
$html .= fxAdminDocButton($docAnchorClef);
|
||
}
|
||
return $html . '</span>';
|
||
}
|
||
|
||
/** 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 '<span class="' . $strClass . '">' . $strInner . '</span>';
|
||
}
|
||
|
||
/** 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;
|
||
}
|
||
|
||
/** MSIN-4446 — Compte les séquences persistées (ignore la ligne UI temporaire epr_bib_id=0). */
|
||
function fxBibCountSavedRanges(array $tabBibRanges) {
|
||
$intCount = 0;
|
||
foreach ($tabBibRanges as $range) {
|
||
if ((int)($range['epr_bib_id'] ?? 0) > 0) {
|
||
$intCount++;
|
||
}
|
||
}
|
||
return $intCount;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4446 — Pastille(s) résumé à renvoyer avec le HTML des séquences (AJAX).
|
||
* Évite que « 1 séquence » reste affiché après delete / save / refresh.
|
||
*/
|
||
function fxBibAssignRangesAjaxExtras($epr_id, array $tabBibRanges) {
|
||
$epr_id = (int)$epr_id;
|
||
$intSeqCount = fxBibCountSavedRanges($tabBibRanges);
|
||
$blnAutoActive = $epr_id > 0 ? fxIsBibAutoActive($epr_id) : false;
|
||
|
||
return [
|
||
'summary_html' => fxBibAssignHeaderSummary($intSeqCount, $blnAutoActive),
|
||
'seq_count' => $intSeqCount,
|
||
'auto_active' => $blnAutoActive ? 1 : 0,
|
||
];
|
||
}
|
||
|
||
/** 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')];
|
||
}
|
||
|
||
if (fxBibProductionEpreuveIsLocked($rowEprId)) {
|
||
return ['success' => false, 'message' => fxBibMsg('bib_v5_production_locked_error')];
|
||
}
|
||
|
||
$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 utilisateur (vert ouvert / rouge fermé) devant une séquence enregistrée. */
|
||
function fxBibRenderRangeLockButton(array $range, $epr_id = 0, $blnDisabled = false) {
|
||
if ((int)($range['epr_bib_id'] ?? 0) <= 0) {
|
||
return '<div class="epr-col-lock"></div>';
|
||
}
|
||
|
||
$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 '<div class="epr-col-lock"><button type="button"'
|
||
. ' class="btn btn-sm btn-bib-lock ' . $strClass . '"'
|
||
. ' data-range-id="' . (int)$range['epr_bib_id'] . '"'
|
||
. ' data-epr-id="' . (int)$epr_id . '"'
|
||
. ' data-locked="' . ($locked ? '1' : '0') . '"'
|
||
. ' aria-pressed="' . ($locked ? 'true' : 'false') . '"'
|
||
. ($blnDisabled ? ' disabled' : '')
|
||
. fxBibTippyAttr($strTip)
|
||
. '>'
|
||
. '<i class="fa ' . $strIcon . '" aria-hidden="true"></i>'
|
||
. '</button></div>';
|
||
}
|
||
|
||
/** MSIN-4469 — Cadenas distinct signalant le verrouillage physique pour impression. */
|
||
function fxBibRenderProductionRangeLock($blnProductionLocked) {
|
||
if (!$blnProductionLocked) {
|
||
return '<div class="epr-col-production-lock"></div>';
|
||
}
|
||
|
||
$strLabel = fxBibTexte('bib_v5_production_print_lock_tip', 0);
|
||
return '<div class="epr-col-production-lock">'
|
||
. '<span class="btn btn-sm btn-bib-production-lock"'
|
||
. ' role="img" tabindex="0"'
|
||
. ' aria-label="' . fxBibEsc($strLabel) . '"'
|
||
. fxBibTippyAttr('bib_v5_production_print_lock_tip')
|
||
. '>'
|
||
. '<i class="fa fa-lock" aria-hidden="true"></i>'
|
||
. '</span></div>';
|
||
}
|
||
|
||
/** 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 '<span class="bib-auto-badge bib-auto-badge--row badge badge-bib-auto-seq"'
|
||
. fxBibTippyAttr('bib_v4_auto')
|
||
. '>'
|
||
. fxBibEsc(fxBibTexte('bib_v4_auto', 0))
|
||
. fxBibTradButton('bib_v4_auto')
|
||
. '</span>';
|
||
}
|
||
|
||
/** MSIN-4436 — Nombre d'équipes actives sur une épreuve équipe. */
|
||
function fxBibCountEquipes($epr_id) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
if ($epr_id <= 0) {
|
||
return 0;
|
||
}
|
||
|
||
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.pec_id > 0
|
||
");
|
||
}
|
||
|
||
/** Pastilles épreuve (solo/équipe, inscrits, avec dossard) — bande bleue colonne gauche. */
|
||
function fxBibEpreuveHeaderSummaries($tabEpreuve, $infoBib) {
|
||
$html = '';
|
||
if ((int)$tabEpreuve['epr_equipe'] === 1) {
|
||
$intNbEquipes = (int)($infoBib['nb_equipes'] ?? 0);
|
||
$html .= fxBibHeaderSummaryBadge(
|
||
fxBibSiteOrBibTexte('promoteur_epr_equipe', 'bib_v4_summary_team'),
|
||
'team',
|
||
'bib_v4_summary_team'
|
||
);
|
||
$html .= '<span class="epr-header-summary epr-header-summary--teams">'
|
||
. '<span class="bib-team-count">' . $intNbEquipes . '</span> '
|
||
. fxBibTexteTrad('bib_v4_summary_teams_unit', 0)
|
||
. '</span>';
|
||
} else {
|
||
$html .= fxBibHeaderSummaryBadge(
|
||
fxBibSiteOrBibTexte('promoteur_epr_solo', 'bib_v4_summary_solo'),
|
||
'solo',
|
||
'bib_v4_summary_solo'
|
||
);
|
||
}
|
||
|
||
$html .= '<span class="epr-header-summary epr-header-summary--insc">'
|
||
. '<span class="bib-total">' . (int)$infoBib['total'] . '</span> '
|
||
. fxBibSiteOrBibTexteTrad('promoteur_qte_epr_qte_ordered', 'bib_v4_summary_registered')
|
||
. '</span>';
|
||
|
||
$html .= '<span class="epr-header-summary epr-header-summary--bib">'
|
||
. '<span class="bib-avec">' . (int)$infoBib['avec_bib'] . '</span> '
|
||
. fxBibSiteOrBibTexteTrad('promoteur_qte_epr_qte_orderedavec_bib', 'bib_v4_summary_with_bib')
|
||
. '</span>';
|
||
|
||
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();
|
||
?>
|
||
<div class="epr-header epr-header--epr-identity">
|
||
<div class="epr-identity-head">
|
||
<div class="epr-epr-title">
|
||
<?php if ($strCat !== '') { ?>
|
||
<span class="epr-epr-title-line epr-epr-title-line--cat"><?php echo fxBibEsc($strCat); ?></span>
|
||
<?php } ?>
|
||
<?php if ($strType !== '') { ?>
|
||
<span class="epr-epr-title-line epr-epr-title-line--type"><?php echo fxBibEsc($strType); ?></span>
|
||
<?php } ?>
|
||
<?php if ($strNom !== '') { ?>
|
||
<span class="epr-epr-title-line epr-epr-title-line--nom"><?php echo fxBibEsc($strNom); ?></span>
|
||
<?php } ?>
|
||
</div>
|
||
<?php echo fxBibRenderViewRangeButton($intEprId, 0, 'btn btn-sm btn-light btn-view-range'); ?>
|
||
</div>
|
||
<span class="epr-header-summaries epr-header-summaries--stacked">
|
||
<?php echo fxBibEpreuveHeaderSummaries($tabEpreuve, $infoBib); ?>
|
||
</span>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4436 — Réinitialiser tous les dossards de l'épreuve (sans sélection de séquences). */
|
||
function renderBibEpreuveResetAllButton($epr_id, $infoBib, $blnHasLockedRanges = false) {
|
||
if ((int)($infoBib['avec_bib'] ?? 0) <= 0) {
|
||
return '';
|
||
}
|
||
|
||
$strTipClef = $blnHasLockedRanges ? 'bib_v4_tip_reset_all_locked' : 'bib_v4_tip_reset_all';
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="epr-identity-reset-all">
|
||
<button type="button"
|
||
class="btn btn-sm btn-danger btn-reset-all-epr"
|
||
data-epr-id="<?php echo (int)$epr_id; ?>"
|
||
<?php echo $blnHasLockedRanges ? ' disabled' : ''; ?>
|
||
<?php echo fxBibTippyAttr($strTipClef); ?>>
|
||
<?php fxBibTexte('bib_v4_reset_all', 1); ?>
|
||
</button>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** Bouton réduire / développer le corps du bloc (en-tête reste visible). */
|
||
function fxBibBlockCollapseToggle($strLangue = 'fr', $blnCollapsed = true) {
|
||
$strCollapse = fxBibTexte('bib_v4_collapse', 0);
|
||
$strExpand = fxBibTexte('bib_v4_expand', 0);
|
||
|
||
if ($blnCollapsed) {
|
||
return '<button type="button" class="epr-block-toggle" aria-expanded="false"'
|
||
. ' data-label-collapse="' . fxBibEsc($strCollapse) . '"'
|
||
. ' data-label-expand="' . fxBibEsc($strExpand) . '"'
|
||
. ' aria-label="' . fxBibEsc($strExpand) . '"'
|
||
. ' title="' . fxBibEsc($strExpand) . '">'
|
||
. '<i class="fa fa-chevron-down" aria-hidden="true"></i></button>';
|
||
}
|
||
|
||
return '<button type="button" class="epr-block-toggle" aria-expanded="true"'
|
||
. ' data-label-collapse="' . fxBibEsc($strCollapse) . '"'
|
||
. ' data-label-expand="' . fxBibEsc($strExpand) . '"'
|
||
. ' aria-label="' . fxBibEsc($strCollapse) . '"'
|
||
. ' title="' . fxBibEsc($strCollapse) . '">'
|
||
. '<i class="fa fa-chevron-up" aria-hidden="true"></i></button>';
|
||
}
|
||
|
||
/** 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 '<span class="' . $strClass . '">'
|
||
. fxBibEsc($strLabel)
|
||
. fxBibAideButton($clef)
|
||
. fxBibTradButton($clef)
|
||
. '</span>';
|
||
}
|
||
|
||
/** Groupe action (bouton + ?) — $strClass ex. « epr-action-batch-group ». */
|
||
function fxBibActionGroupOpen($strClass, $blnVisible = true) {
|
||
return '<span class="epr-action-group ' . fxBibEsc(trim($strClass)) . fxBibUiHiddenClass($blnVisible) . '">';
|
||
}
|
||
|
||
function fxBibActionGroupClose() {
|
||
return '</span>';
|
||
}
|
||
|
||
/** 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 '<span class="' . $strClass . '">';
|
||
}
|
||
|
||
function fxBibBtnAideSegmentClose($clef = '') {
|
||
$html = '';
|
||
if ($clef !== '') {
|
||
$html .= fxBibTradButton($clef);
|
||
}
|
||
return $html . '</span>';
|
||
}
|
||
|
||
/** MSIN-4468 — Capacité totale modifiable; disponibilité dérivée en lecture seule. */
|
||
function renderBibGestionEpreuve($epr_id, $int_eve_id, $strLangue) {
|
||
$epr_id = (int)$epr_id;
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$arrQuantites = fxGetQuantites($epr_id);
|
||
$tabEpreuve = fxGetEpreuve($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;
|
||
$blnQteLimitee = intval($tabEpreuve['epr_qte_limitee'] ?? 0) === 1;
|
||
$blnCanEditQte = !empty($_SESSION['usa_id'])
|
||
|| (!empty($_SESSION['com_id'])
|
||
&& function_exists('fxEveAccesHasPermission')
|
||
&& fxEveAccesHasPermission($_SESSION['com_id'], $int_eve_id, 'epreuves.edit_qte'));
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="epr-gestion-panel" data-epr-id="<?php echo $epr_id; ?>" data-qte-inscrits="<?php echo (int)$arrQuantites['qte_inscrits']; ?>">
|
||
<dl class="epr-gestion-stats">
|
||
<div class="epr-gestion-stat">
|
||
<dt><?php afficheTexte('promoteur_qte_epr_qte_total'); ?></dt>
|
||
<?php if ($blnQteLimitee && $blnCanEditQte) { ?>
|
||
<?php fxShowAjouterQuantiteTotaleV4($epr_id, (int)$arrQuantites['qte_courante']); ?>
|
||
<?php } else { ?>
|
||
<dd id="qte_courante_<?php echo $epr_id; ?>">
|
||
<?php
|
||
if ($blnQteLimitee) {
|
||
echo (int)$arrQuantites['qte_courante'];
|
||
} else {
|
||
afficheTexte('promoteur_hub_unlimited');
|
||
}
|
||
?>
|
||
</dd>
|
||
<?php } ?>
|
||
</div>
|
||
<div class="epr-gestion-stat">
|
||
<dt><?php afficheTexte('promoteur_qte_epr_qte_ordered'); ?></dt>
|
||
<dd id="qte_inscrits_<?php echo $epr_id; ?>"><?php echo (int)$arrQuantites['qte_inscrits']; ?></dd>
|
||
</div>
|
||
<div class="epr-gestion-stat">
|
||
<dt><?php afficheTexte('promoteur_qte_checkin'); ?></dt>
|
||
<dd id="qte_checkin_<?php echo $epr_id; ?>"><?php echo (int)$QCheckin; ?></dd>
|
||
</div>
|
||
<div class="epr-gestion-stat epr-gestion-stat--dispo">
|
||
<dt><?php afficheTexte('promoteur_qte_epr_qte'); ?></dt>
|
||
<dd id="qte_restante_<?php echo $epr_id; ?>">
|
||
<?php echo $blnQteLimitee ? (int)$arrQuantites['qte_restante'] : '—'; ?>
|
||
</dd>
|
||
</div>
|
||
</dl>
|
||
|
||
<div class="epr-gestion-lattente">
|
||
<div class="epr-gestion-lattente-action">
|
||
<?php fx_liste_attente_btactiver($int_eve_id, $epr_id, 'gestion'); ?>
|
||
</div>
|
||
<dl class="epr-gestion-lattente-counts">
|
||
<div>
|
||
<dt><?php afficheTexte('promoteur_lattente_nb'); ?></dt>
|
||
<dd><?php echo $intNbSurListeA > 0 ? $intNbSurListeA : '—'; ?></dd>
|
||
</div>
|
||
<div>
|
||
<dt><?php afficheTexte('promoteur_lattente_nbtotal'); ?></dt>
|
||
<dd><?php echo $intNbSurListe > 0 ? $intNbSurListe : '—'; ?></dd>
|
||
</div>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** Bouton « ajouter séquence » — libellé BD (bib_v4_add) + tip court + aide longue. */
|
||
function renderBibAddRangeButton($epr_id) {
|
||
ob_start();
|
||
?>
|
||
<div class="epr-add-range-row">
|
||
<?php echo fxBibActionGroupOpen('epr-add-range-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button"
|
||
class="btn btn-success btn-sm btn-add-range"
|
||
data-epr-id="<?php echo (int)$epr_id; ?>"<?php echo fxBibTippyAttr('bib_v4_tip_add'); ?>>
|
||
<?php fxBibTexte('bib_v4_add', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_add', 'success', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_add'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4429 — Valeurs dérivées pour affichage Qté (colonne séparée de Fin). */
|
||
function fxBibRangeSpecValues(array $range) {
|
||
$intStart = (int)($range['epr_bib_start'] ?? 0);
|
||
$intEnd = (int)($range['epr_bib_finish'] ?? 0);
|
||
$intId = (int)($range['epr_bib_id'] ?? 0);
|
||
$intQty = '';
|
||
|
||
if ($intStart > 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();
|
||
?>
|
||
<div class="epr-col-or" aria-hidden="true">
|
||
<span class="bib-range-or"><?php fxBibTexte('bib_v4_range_or', 1); ?></span>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** En-tête colonnes séquences — répété par épreuve, inclus dans renderBibRanges (y compris AJAX). */
|
||
function renderBibRangeHeader() {
|
||
ob_start();
|
||
?>
|
||
<div class="epr-line epr-line-header">
|
||
<div class="epr-col-lock"><?php echo fxBibColHeader('bib_v4_col_lock'); ?></div>
|
||
<div class="epr-col-production-lock"><?php echo fxBibColHeader('bib_v5_production_print_lock_col'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_view'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_start'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_qty'); ?></div>
|
||
<?php echo fxBibRenderRangeOrCell(); ?>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_end'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_ok'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_del'); ?></div>
|
||
<div class="epr-col-stats">
|
||
<div><?php echo fxBibColHeader('bib_v4_col_last'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_used'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_avail'); ?></div>
|
||
</div>
|
||
<div class="epr-col-batch"></div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** Boutons assignation / reset / auto — fusionnés dans la boîte Assignation de dossard. */
|
||
function renderBibAssignActions($epr_id, $eve_id, $strLangue, $infoBib, $blnAutoActive, $blnTeamEpreuve, $blnHasSequences = false, array $tabEpreuve = []) {
|
||
$blnShowReset = $blnHasSequences && (int)$infoBib['avec_bib'] > 0;
|
||
ob_start();
|
||
?>
|
||
<div class="epr-actions">
|
||
<div class="bib-assignment-methods">
|
||
<section class="bib-assignment-method">
|
||
<h4><?php fxBibTexteTrad('bib_v5_batch_title', 1); ?></h4>
|
||
<p><?php fxBibTexteTrad('bib_v5_batch_hint', 1); ?></p>
|
||
<?php echo fxBibActionGroupOpen('epr-action-batch-group', $blnHasSequences); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-primary btn-assign-batch"<?php echo fxBibTippyAttr('bib_v4_tip_assign_seq'); ?>>
|
||
<?php fxBibTexte('bib_v4_assign_seq', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_assign_seq', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_assign_seq'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</section>
|
||
|
||
<section class="bib-assignment-method">
|
||
<h4><?php fxBibTexteTrad('bib_v5_auto_title', 1); ?></h4>
|
||
<p><?php fxBibTexteTrad('bib_v5_auto_hint', 1); ?></p>
|
||
<?php echo fxBibActionGroupOpen('epr-action-auto-group', $blnHasSequences); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button"
|
||
class="btn btn-sm btn-secondary btn-auto btn-bib-auto<?php echo $blnAutoActive ? ' btn-bib-auto--active' : ''; ?>"<?php echo fxBibTippyAttr('bib_v4_tip_auto'); ?>>
|
||
<?php echo fxBibEsc($blnAutoActive ? fxBibTexte('bib_v4_auto_config', 0) : fxBibTexte('bib_v4_auto', 0)); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_auto', 'auto', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose($blnAutoActive ? 'bib_v4_auto_config' : 'bib_v4_auto'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</section>
|
||
</div>
|
||
|
||
<div class="bib-advanced-actions<?php echo $blnShowReset ? '' : ' bib-ui-hidden'; ?>">
|
||
<span class="bib-advanced-actions__title"><?php fxBibTexteTrad('bib_v5_advanced_actions', 1); ?></span>
|
||
<?php echo fxBibActionGroupOpen('epr-action-reset-group', $blnShowReset); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button"
|
||
class="btn btn-sm btn-danger btn-reset"<?php echo fxBibTippyAttr('bib_v4_tip_reset'); ?>>
|
||
<?php fxBibTexte('bib_v4_reset', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_reset', 'danger', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_reset'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
|
||
<?php echo renderBibBatchPickPrompt(); ?>
|
||
|
||
<div class="auto-config-container bib-ui-hidden">
|
||
<div class="auto-config-ready bib-ui-hidden">
|
||
<?php echo fxBibActionGroupOpen('epr-auto-info-group text-muted small mb-2'); ?>
|
||
<span class="auto-info-text"><?php fxBibTexteTrad('bib_v4_auto_select_hint', 1); ?></span>
|
||
<?php echo fxBibAideButton('bib_v4_auto_select_hint', '', false); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
<div class="epr-action-row epr-action-row-auto-config">
|
||
<div class="epr-action-row-auto-left">
|
||
<?php echo fxBibActionGroupOpen('epr-action-accept-auto-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-success btn-accepter-auto"><?php fxBibTexte('bib_v4_auto_accept', 1); ?></button>
|
||
<?php echo fxBibAideButton('bib_v4_auto_accept', 'success', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_auto_accept'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="epr-action-row epr-action-row-auto-footer">
|
||
<?php echo fxBibActionGroupOpen('epr-action-cancel-auto-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-annuler-auto"><?php fxBibTexte('bib_v4_auto_cancel', 1); ?></button>
|
||
<?php echo fxBibAideButton('bib_v4_auto_cancel', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_auto_cancel'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
<?php echo fxBibActionGroupOpen('epr-action-desactiver-group', $blnAutoActive); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-danger btn-desactiver-auto">
|
||
<?php fxBibTexte('bib_v4_auto_disable', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_auto_disable', 'danger', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_auto_disable'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="batch-config-container bib-ui-hidden">
|
||
<?php
|
||
list($strSort1, $strSort2) = fxBibGetEpreuveDefaultSortKeys($tabEpreuve);
|
||
echo renderBatchConfig((int)$epr_id, (int)$eve_id, $strLangue, $blnTeamEpreuve, $strSort1, $strSort2);
|
||
?>
|
||
<div class="epr-action-row">
|
||
<?php echo fxBibActionGroupOpen('epr-action-sim-group', false); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-simuler-batch">
|
||
<?php fxBibTexte('bib_v4_batch_simulate', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_simulate', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_simulate'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
<?php echo fxBibActionGroupOpen('epr-action-go-group', false); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-success btn-go-batch">
|
||
<?php fxBibTexte('bib_v4_batch_go', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_go', 'success', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_go'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4436 — Séquences débloquées avec place pour le batch global (épreuves solo).
|
||
*/
|
||
function fxBibGetSelectableRangesForGlobalBatch($epr_id) {
|
||
$rows = fxInfosBibRange((int)$epr_id);
|
||
$out = [];
|
||
|
||
foreach ($rows as $row) {
|
||
if (fxBibRangeIsLocked($row)) {
|
||
continue;
|
||
}
|
||
|
||
$intTotal = (int)($row['nb_total_range'] ?? 0);
|
||
$intUsed = (int)($row['nb_utilises'] ?? 0);
|
||
$intDispo = max(0, $intTotal - $intUsed);
|
||
$intBibId = (int)($row['epr_bib_id'] ?? 0);
|
||
|
||
if ($intBibId <= 0 || $intDispo <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$out[] = [
|
||
'epr_bib_id' => $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-4440 — Pastille tuile Anomalies (style Inter épreuve, sans compteur rouge). */
|
||
function renderBibAnomaliesNavBadge($intCount = 0, $blnPending = false) {
|
||
if ($blnPending || (int)$intCount <= 0) {
|
||
return '<span class="epr-header-summary bib-event-config-note bib-anomalies-nav-badge'
|
||
. fxBibUiHiddenClass(true)
|
||
. '" data-bib-anomalies-nav-badge="1" aria-hidden="true"></span>';
|
||
}
|
||
|
||
$strLabel = fxBibMsg('bib_v4_anomalies_nav_todo_fmt', (int)$intCount);
|
||
if ($strLabel === '' || $strLabel === 'bib_v4_anomalies_nav_todo_fmt') {
|
||
$strLabel = fxBibTexte('bib_v4_anomalies_nav_todo', 0) . ' : ' . (int)$intCount;
|
||
}
|
||
|
||
return '<span class="epr-header-summary bib-event-config-note bib-anomalies-nav-badge"'
|
||
. ' data-bib-anomalies-nav-badge="1"'
|
||
. ' data-bib-anomalies-nav-count="' . (int)$intCount . '"'
|
||
. ' title="' . fxBibEsc($strLabel) . '">'
|
||
. fxBibEsc($strLabel)
|
||
. '</span>';
|
||
}
|
||
|
||
/**
|
||
* MSIN-4440 — Bouton tuile de la grille outils bib v4.
|
||
*/
|
||
function renderBibToolNavBtn($strTool, $strTitleClef, $strBadgesHtml = '', $blnAlt = false, $strDocClef = '') {
|
||
$strClass = 'bib-tool-btn';
|
||
if ($blnAlt) {
|
||
$strClass .= ' bib-tool-btn--alt';
|
||
}
|
||
|
||
$strTitle = fxBibTexte($strTitleClef, 0);
|
||
|
||
// div role=button : évite button dans button (icônes aide/doc) — HTML invalide qui casse la grille.
|
||
$html = '<div class="' . $strClass . '"'
|
||
. ' role="button"'
|
||
. ' tabindex="0"'
|
||
. ' data-bib-tool="' . fxBibEsc($strTool) . '"'
|
||
. ' data-bib-tool-label="' . fxBibEsc($strTitle) . '"'
|
||
. ' aria-expanded="false">';
|
||
|
||
$html .= '<span class="bib-tool-btn__main">';
|
||
$html .= '<span class="bib-tool-btn__label">';
|
||
$html .= '<span class="bib-tool-btn__label-text">' . fxBibEsc($strTitle) . '</span>';
|
||
$html .= '<span class="bib-tool-btn__actions">';
|
||
$html .= fxBibAideButton($strTitleClef);
|
||
if ($strDocClef !== '') {
|
||
$html .= fxDocRenderTrigger($strDocClef);
|
||
$html .= fxAdminDocButton($strDocClef);
|
||
}
|
||
$html .= '</span>';
|
||
$html .= '</span>';
|
||
|
||
if ($strBadgesHtml !== '') {
|
||
$html .= '<span class="bib-tool-btn__badges">' . $strBadgesHtml . '</span>';
|
||
}
|
||
|
||
$html .= '</span></div>';
|
||
return $html;
|
||
}
|
||
|
||
/** MSIN-4467 — Onglet principal de l'espace de travail dossards. */
|
||
function renderBibWorkspaceTab($strWorkspace, $strTitleClef, $blnActive = false) {
|
||
$strClass = 'bib-workspace-tab' . ($blnActive ? ' is-active' : '');
|
||
return '<button type="button" class="' . $strClass . '"'
|
||
. ' data-bib-workspace="' . fxBibEsc($strWorkspace) . '"'
|
||
. ' aria-selected="' . ($blnActive ? 'true' : 'false') . '"'
|
||
. ' role="tab">'
|
||
. fxBibEsc(fxBibTexte($strTitleClef, 0))
|
||
. fxBibTradButton($strTitleClef)
|
||
. '</button>';
|
||
}
|
||
|
||
/** MSIN-4467 — Résumé événement affiché avant le détail des épreuves. */
|
||
function renderBibPreparationOverview(array $tabEpreuves, $strAnomBadges = '') {
|
||
$intRegistered = 0;
|
||
$intAssigned = 0;
|
||
|
||
foreach ($tabEpreuves as $tabEpreuve) {
|
||
if (!is_array($tabEpreuve)) {
|
||
continue;
|
||
}
|
||
$tabInfo = fxInfosBibEpreuve((int)($tabEpreuve['epr_id'] ?? 0));
|
||
$intRegistered += (int)($tabInfo['total'] ?? 0);
|
||
$intAssigned += (int)($tabInfo['avec_bib'] ?? 0);
|
||
}
|
||
|
||
$intPending = max(0, $intRegistered - $intAssigned);
|
||
$tabQuantityStats = [
|
||
['value' => count($tabEpreuves), 'key' => 'bib_v5_stat_races', 'tone' => ''],
|
||
['value' => $intRegistered, 'key' => 'bib_v5_stat_registered', 'tone' => ''],
|
||
];
|
||
$tabBibStats = [
|
||
['value' => $intAssigned, 'key' => 'bib_v5_stat_assigned', 'tone' => 'success'],
|
||
['value' => $intPending, 'key' => 'bib_v5_stat_pending', 'tone' => $intPending > 0 ? 'warning' : 'success'],
|
||
];
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="bib-preparation-overview">
|
||
<div class="bib-workspace-panel-heading">
|
||
<p><?php fxBibTexteTrad('bib_v5_preparation_intro', 1); ?></p>
|
||
</div>
|
||
<div class="bib-preparation-groups">
|
||
<section class="bib-preparation-group bib-preparation-group--quantities">
|
||
<h3><?php fxBibTexteTrad('bib_v5_group_quantities', 1); ?></h3>
|
||
<dl class="bib-preparation-stats">
|
||
<?php foreach ($tabQuantityStats as $tabStat) { ?>
|
||
<div class="bib-preparation-stat">
|
||
<dd data-bib-overview-stat="<?php echo fxBibEsc($tabStat['key']); ?>"><?php echo (int)$tabStat['value']; ?></dd>
|
||
<dt><?php fxBibTexteTrad($tabStat['key'], 1); ?></dt>
|
||
</div>
|
||
<?php } ?>
|
||
</dl>
|
||
<nav class="bib-tool-nav bib-tool-nav--group" aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v5_group_quantities', 0)); ?>">
|
||
<?php echo renderBibToolNavBtn('qty_summary', 'bib_v4_qty_summary_title'); ?>
|
||
</nav>
|
||
</section>
|
||
|
||
<section class="bib-preparation-group bib-preparation-group--bibs">
|
||
<h3><?php fxBibTexteTrad('bib_v5_group_bibs', 1); ?></h3>
|
||
<dl class="bib-preparation-stats">
|
||
<?php foreach ($tabBibStats as $tabStat) { ?>
|
||
<div class="bib-preparation-stat<?php echo $tabStat['tone'] !== '' ? ' bib-preparation-stat--' . fxBibEsc($tabStat['tone']) : ''; ?>">
|
||
<dd data-bib-overview-stat="<?php echo fxBibEsc($tabStat['key']); ?>"><?php echo (int)$tabStat['value']; ?></dd>
|
||
<dt><?php fxBibTexteTrad($tabStat['key'], 1); ?></dt>
|
||
</div>
|
||
<?php } ?>
|
||
</dl>
|
||
<nav class="bib-tool-nav bib-tool-nav--group" aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v5_group_bibs', 0)); ?>">
|
||
<?php echo renderBibToolNavBtn('anomalies', 'bib_v4_anomalies_title', $strAnomBadges); ?>
|
||
</nav>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4467 / MSIN-4469 — Production physique et fichier officiel Excel. */
|
||
function renderBibProductionPreview(array $tabEpreuves, $strLangue = 'fr') {
|
||
global $vDomaine;
|
||
|
||
$intEveId = 0;
|
||
$intRangeTotal = 0;
|
||
foreach ($tabEpreuves as $tabEpreuve) {
|
||
if (!is_array($tabEpreuve)) {
|
||
continue;
|
||
}
|
||
if ($intEveId <= 0) {
|
||
$intEveId = (int)($tabEpreuve['eve_id'] ?? 0);
|
||
}
|
||
$intRangeTotal += fxBibCountSavedRanges(
|
||
fxInfosBibRange((int)($tabEpreuve['epr_id'] ?? 0), 0, false)
|
||
);
|
||
}
|
||
|
||
$tabProductionOrder = $intEveId > 0 ? fxBibProductionGetActiveOrder($intEveId) : null;
|
||
$blnProductionLocked = !empty($tabProductionOrder);
|
||
$strExcelUrl = $vDomaine . '/bib_production_excel.php';
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="bib-production-preview">
|
||
<div class="bib-workspace-panel-heading">
|
||
<p><?php fxBibTexteTrad('bib_v5_production_intro', 1); ?></p>
|
||
</div>
|
||
|
||
<section class="bib-production-excel epr-block">
|
||
<div class="epr-header">
|
||
<span class="epr-header-label">
|
||
<?php fxBibTexteTrad('bib_v5_production_excel_title', 1); ?>
|
||
</span>
|
||
</div>
|
||
<div class="epr-content">
|
||
<p><?php fxBibTexteTrad('bib_v5_production_excel_intro', 1); ?></p>
|
||
<?php if ($blnProductionLocked) { ?>
|
||
<p class="bib-production-category__status">
|
||
<i class="fa fa-lock mr-1" aria-hidden="true"></i>
|
||
<?php fxBibTexteTrad('bib_v5_production_excel_locked', 1); ?>
|
||
</p>
|
||
<p class="text-muted small">
|
||
<?php echo fxBibEsc(fxBibMsg(
|
||
'bib_v5_production_excel_meta',
|
||
(int)($tabProductionOrder['bpo_version'] ?? 1),
|
||
(string)($tabProductionOrder['bpo_created_at'] ?? ''),
|
||
(string)($tabProductionOrder['bpo_created_by'] ?? '')
|
||
)); ?>
|
||
</p>
|
||
|
||
<?php if (($tabProductionOrder['bpo_status'] ?? '') === 'ready') { ?>
|
||
<form method="post" action="<?php echo fxBibEsc($strExcelUrl); ?>" target="_blank"
|
||
class="bib-production-return-preparation-form">
|
||
<input type="hidden" name="action" value="download">
|
||
<input type="hidden" name="eve_id" value="<?php echo $intEveId; ?>">
|
||
<input type="hidden" name="order_id" value="<?php echo (int)$tabProductionOrder['bpo_id']; ?>">
|
||
<input type="hidden" name="csrf_token" value="<?php echo fxBibEsc(fxBibCsrfToken()); ?>">
|
||
<input type="hidden" name="lang" value="<?php echo fxBibEsc($strLangue); ?>">
|
||
<button type="submit" class="btn btn-primary btn-sm">
|
||
<i class="fa fa-download mr-1" aria-hidden="true"></i>
|
||
<?php fxBibTexteTrad('bib_v5_production_excel_download', 1); ?>
|
||
</button>
|
||
</form>
|
||
<?php } else { ?>
|
||
<p class="text-muted small"><?php fxBibTexteTrad('bib_v5_production_excel_generating', 1); ?></p>
|
||
<?php } ?>
|
||
|
||
<?php // MSIN-4469 — Déverrouiller : droit promoteur (dossards.manage), pas seulement superadmin. ?>
|
||
<div class="mt-3">
|
||
<p class="text-muted small mb-1"><?php fxBibTexteTrad('bib_v5_production_dev_unlock_help', 1); ?></p>
|
||
<form method="post" action="<?php echo fxBibEsc($strExcelUrl); ?>">
|
||
<input type="hidden" name="action" value="development_unlock">
|
||
<input type="hidden" name="eve_id" value="<?php echo $intEveId; ?>">
|
||
<input type="hidden" name="csrf_token" value="<?php echo fxBibEsc(fxBibCsrfToken()); ?>">
|
||
<input type="hidden" name="lang" value="<?php echo fxBibEsc($strLangue); ?>">
|
||
<button type="submit" class="btn btn-warning btn-sm">
|
||
<i class="fa fa-unlock mr-1" aria-hidden="true"></i>
|
||
<?php fxBibTexteTrad('bib_v5_production_dev_unlock', 1); ?>
|
||
</button>
|
||
</form>
|
||
</div>
|
||
<?php } elseif ($intRangeTotal > 0) { ?>
|
||
<p class="text-muted small"><?php fxBibTexteTrad('bib_v5_production_excel_generate_help', 1); ?></p>
|
||
<form method="post" action="<?php echo fxBibEsc($strExcelUrl); ?>" target="_blank"
|
||
class="bib-production-return-preparation-form">
|
||
<input type="hidden" name="action" value="generate">
|
||
<input type="hidden" name="eve_id" value="<?php echo $intEveId; ?>">
|
||
<input type="hidden" name="csrf_token" value="<?php echo fxBibEsc(fxBibCsrfToken()); ?>">
|
||
<input type="hidden" name="lang" value="<?php echo fxBibEsc($strLangue); ?>">
|
||
<button type="submit" class="btn btn-primary btn-sm">
|
||
<i class="fa fa-file-excel-o mr-1" aria-hidden="true"></i>
|
||
<?php fxBibTexteTrad('bib_v5_production_excel_generate', 1); ?>
|
||
</button>
|
||
</form>
|
||
<?php } else { ?>
|
||
<p class="text-muted small"><?php fxBibTexteTrad('bib_v5_production_no_ranges', 1); ?></p>
|
||
<?php } ?>
|
||
</div>
|
||
</section>
|
||
|
||
<ol class="bib-production-steps" aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v5_workspace_production', 0)); ?>">
|
||
<?php
|
||
$tabStepKeys = [
|
||
'bib_v5_production_step_ranges',
|
||
'bib_v5_production_step_answers',
|
||
'bib_v5_production_step_review',
|
||
'bib_v5_production_step_printer',
|
||
];
|
||
foreach ($tabStepKeys as $intIndex => $strStepKey) { ?>
|
||
<li>
|
||
<span class="bib-production-step-number"><?php echo $intIndex + 1; ?></span>
|
||
<span><?php fxBibTexteTrad($strStepKey, 1); ?></span>
|
||
</li>
|
||
<?php } ?>
|
||
</ol>
|
||
|
||
<div class="bib-production-category-heading">
|
||
<h3><?php fxBibTexteTrad('bib_v5_production_categories', 1); ?></h3>
|
||
</div>
|
||
<div class="bib-production-category-list">
|
||
<?php foreach ($tabEpreuves as $tabEpreuve) {
|
||
if (!is_array($tabEpreuve)) {
|
||
continue;
|
||
}
|
||
$intEprId = (int)($tabEpreuve['epr_id'] ?? 0);
|
||
$intRangeCount = fxBibCountSavedRanges(fxInfosBibRange($intEprId, 0, false));
|
||
?>
|
||
<article class="bib-production-category" data-epr-id="<?php echo $intEprId; ?>">
|
||
<div class="bib-production-category__identity">
|
||
<strong><?php echo fxBibEsc(fxBibEpreuveDisplayName($tabEpreuve, $strLangue)); ?></strong>
|
||
<span><?php echo fxBibEsc(trim($tabEpreuve['epr_nom_' . $strLangue] ?? '')); ?></span>
|
||
</div>
|
||
<dl class="bib-production-category__fields">
|
||
<div>
|
||
<dt><?php fxBibTexteTrad('bib_v5_production_ranges', 1); ?></dt>
|
||
<dd class="bib-production-range-count"><?php echo $intRangeCount; ?></dd>
|
||
</div>
|
||
<div>
|
||
<dt><?php fxBibTexteTrad('bib_v5_production_color', 1); ?></dt>
|
||
<dd><?php fxBibTexteTrad('bib_v5_production_to_define', 1); ?></dd>
|
||
</div>
|
||
<div>
|
||
<dt><?php fxBibTexteTrad('bib_v5_production_questions', 1); ?></dt>
|
||
<dd><?php fxBibTexteTrad('bib_v5_production_to_define', 1); ?></dd>
|
||
</div>
|
||
</dl>
|
||
<span class="bib-production-category__status">
|
||
<?php
|
||
if ($blnProductionLocked) {
|
||
fxBibTexteTrad('bib_v5_production_excel_locked', 1);
|
||
} else {
|
||
fxBibTexteTrad('bib_v5_production_status', 1);
|
||
}
|
||
?>
|
||
</span>
|
||
</article>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4440 / MSIN-4467 / MSIN-4470 / MSIN-4475 — Espaces principaux + outils et panneau de détail unique.
|
||
*/
|
||
function renderBibToolNav($int_eve_id, $tabEpreuves, $strLangue = 'fr') {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$blnAllow = fxBibEventAllowsInterEprDuplicates($int_eve_id);
|
||
$intSolo = 0;
|
||
|
||
foreach ($tabEpreuves as $epr) {
|
||
if ((int)($epr['epr_equipe'] ?? 0) !== 1) {
|
||
$intSolo++;
|
||
}
|
||
}
|
||
|
||
$strEventBadges = renderBibEventConfigHeaderNote($blnAllow);
|
||
$strAnomBadges = renderBibAnomaliesNavBadge(0, true);
|
||
|
||
$strNavLabel = fxBibTexte('bib_v5_workspace_label', 0);
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="bib-tool-hub">
|
||
<div class="bib-workspace-bar">
|
||
<nav class="bib-workspace-nav" role="tablist" aria-label="<?php echo fxBibEsc($strNavLabel); ?>">
|
||
<?php echo renderBibWorkspaceTab('preparation', 'bib_v5_workspace_preparation', true); ?>
|
||
<?php echo renderBibWorkspaceTab('operations', 'bib_v5_workspace_operations'); ?>
|
||
<?php echo renderBibWorkspaceTab('settings', 'bib_v5_workspace_settings'); ?>
|
||
<?php echo renderBibWorkspaceTab('production', 'bib_v5_workspace_production'); ?>
|
||
</nav>
|
||
<div class="bib-workspace-action">
|
||
<?php echo renderBibToolNavBtn('dist_print', 'bib_v4_dist_print_title'); ?>
|
||
</div>
|
||
</div>
|
||
|
||
<section class="bib-workspace-panel" data-bib-workspace-panel="preparation">
|
||
<?php echo renderBibPreparationOverview($tabEpreuves, $strAnomBadges); ?>
|
||
</section>
|
||
|
||
<section class="bib-workspace-panel bib-ui-hidden" data-bib-workspace-panel="production">
|
||
<?php echo renderBibProductionPreview($tabEpreuves, $strLangue); ?>
|
||
</section>
|
||
|
||
<?php
|
||
// MSIN-4475 — Pas de tuile intermédiaire : les modes s'ouvrent dès l'entrée dans l'onglet.
|
||
$blnOpsAutoGlobal = fxBibGlobalBatchToolIsAvailable($int_eve_id, $tabEpreuves);
|
||
$strOpsAutoLabel = $blnOpsAutoGlobal ? fxBibTexte('bib_v4_global_batch_title', 0) : '';
|
||
?>
|
||
<section class="bib-workspace-panel bib-ui-hidden"
|
||
data-bib-workspace-panel="operations"
|
||
<?php if ($blnOpsAutoGlobal) { ?>
|
||
data-bib-auto-tool="global_batch"
|
||
data-bib-auto-tool-label="<?php echo fxBibEsc($strOpsAutoLabel); ?>"
|
||
<?php } ?>>
|
||
<div class="bib-workspace-panel-heading">
|
||
<p><?php fxBibTexteTrad('bib_v5_modes_intro', 1); ?></p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="bib-workspace-panel bib-ui-hidden" data-bib-workspace-panel="settings">
|
||
<div class="bib-workspace-panel-heading">
|
||
<p><?php fxBibTexteTrad('bib_v5_settings_intro', 1); ?></p>
|
||
</div>
|
||
<nav class="bib-tool-nav bib-tool-nav--settings" aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v5_workspace_settings', 0)); ?>">
|
||
<?php echo renderBibToolNavBtn('event_config', 'bib_v4_event_config_title', $strEventBadges); ?>
|
||
</nav>
|
||
</section>
|
||
|
||
<div id="bib-tool-detail-default-slot" aria-hidden="true"></div>
|
||
<div id="bib-tool-detail" class="bib-tool-detail bib-ui-hidden" aria-live="polite">
|
||
<div class="bib-tool-detail__header epr-header">
|
||
<span id="bib-tool-detail-title" class="bib-tool-detail__title"></span>
|
||
<button type="button"
|
||
class="bib-tool-detail__close epr-block-toggle"
|
||
aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_view_close', 0)); ?>"
|
||
title="<?php echo fxBibEsc(fxBibTexte('bib_v4_view_close', 0)); ?>">
|
||
<i class="fa fa-times" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
<div id="bib-tool-detail-body" class="bib-tool-detail__body"></div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// MSIN-4443 — Assignation globale sans séquence (module dédié).
|
||
require_once __DIR__ . '/inc_fx_bib_global_generated.php';
|
||
// MSIN-4445 — Assignation globale libre (sans création de séquence).
|
||
require_once __DIR__ . '/inc_fx_bib_global_free.php';
|
||
|
||
/**
|
||
* MSIN-4436 / MSIN-4443 — Coquille assignation globale (chargement différé à l'ouverture).
|
||
*/
|
||
function renderBibGlobalBatchPanelShell($int_eve_id, $tabEpreuves, $strLangue) {
|
||
if (!fxBibGlobalBatchToolIsAvailable($int_eve_id, $tabEpreuves)) {
|
||
return '';
|
||
}
|
||
|
||
ob_start();
|
||
?>
|
||
<div id="bib-global-batch-mount">
|
||
<div id="bib-global-batch"
|
||
class="bib-global-batch bib-tool-panel"
|
||
data-bib-tool="global_batch"
|
||
data-global-batch-deferred="1">
|
||
<div class="bib-global-batch__body bib-ui-hidden"></div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4443 — En-tête repliable d'une section assignation globale.
|
||
*/
|
||
function fxBibGlobalBatchSectionOpen($strMode, $strTitleClef, $strLangue = 'fr') {
|
||
$strMode = preg_replace('/[^a-z_]/', '', (string)$strMode);
|
||
ob_start();
|
||
?>
|
||
<section class="bib-global-batch__section bib-global-batch--<?php echo fxBibEsc($strMode); ?> epr-block is-collapsed"
|
||
data-global-batch-section="<?php echo fxBibEsc($strMode); ?>">
|
||
<div class="epr-header bib-global-batch__section-header epr-header--collapsible"
|
||
role="button"
|
||
tabindex="0"
|
||
aria-expanded="false">
|
||
<span class="epr-header-label bib-global-batch__section-header-label">
|
||
<?php fxBibTexteTrad($strTitleClef, 1); ?>
|
||
<?php echo fxBibAideButton($strTitleClef); ?>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-global-batch__section-content">
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4443 — Fermeture section repliable assignation globale. */
|
||
function fxBibGlobalBatchSectionClose() {
|
||
return '</div></section>';
|
||
}
|
||
|
||
/**
|
||
* MSIN-4443 — Enveloppe résultats simulation assignation globale (bouton Fermer).
|
||
*/
|
||
function fxBibWrapGlobalSimView($strSummary, $strSectionsHtml, $strExtraClass = '') {
|
||
$strExtraClass = trim((string)$strExtraClass);
|
||
$strClass = 'epr-row-view bib-global-sim-view';
|
||
if ($strExtraClass !== '') {
|
||
$strClass .= ' ' . preg_replace('/[^a-z0-9 _-]/', '', $strExtraClass);
|
||
}
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="<?php echo fxBibEsc($strClass); ?>">
|
||
<div class="bib-global-sim-view__toolbar">
|
||
<span class="bib-global-sim-view__title"><?php fxBibTexte('bib_v4_ajax_title_simulation', 1); ?></span>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-close-view">
|
||
<?php fxBibTexte('bib_v4_view_close', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_view_close', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_view_close'); ?>
|
||
</div>
|
||
<div class="bib-global-sim-view__summary"><?php echo fxBibEsc($strSummary); ?></div>
|
||
<?php echo $strSectionsHtml; ?>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4436 — Bloc assignation avec séquences existantes.
|
||
*/
|
||
function renderBibGlobalBatchPanelExisting($int_eve_id, $tabEpreuves, $strLangue) {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$tabSolo = [];
|
||
|
||
foreach ($tabEpreuves as $epr) {
|
||
if ((int)($epr['epr_equipe'] ?? 0) === 1) {
|
||
continue;
|
||
}
|
||
|
||
$tabRanges = fxBibGetSelectableRangesForGlobalBatch((int)$epr['epr_id']);
|
||
if (empty($tabRanges)) {
|
||
continue;
|
||
}
|
||
|
||
$tabSolo[] = [
|
||
'epreuve' => $epr,
|
||
'ranges' => $tabRanges,
|
||
];
|
||
}
|
||
|
||
ob_start();
|
||
echo fxBibGlobalBatchSectionOpen('existing', 'bib_v4_global_batch_existing_title', $strLangue);
|
||
|
||
if (count($tabSolo) < 2) { ?>
|
||
<p class="bib-global-batch__unavailable text-muted small mb-0">
|
||
<?php fxBibTexteTrad('bib_v4_global_batch_need_two', 1); ?>
|
||
</p>
|
||
<?php } else { ?>
|
||
<p class="bib-global-batch__hint text-muted small mb-2"><?php fxBibTexteTrad('bib_v4_global_batch_hint', 1); ?></p>
|
||
<p class="bib-global-batch__team-note text-muted small mb-3"><?php fxBibTexteTrad('bib_v4_global_batch_team_note', 1); ?></p>
|
||
|
||
<div class="bib-global-batch__epreuves">
|
||
<?php foreach ($tabSolo as $item) {
|
||
$epr = $item['epreuve'];
|
||
$eprId = (int)$epr['epr_id'];
|
||
$strLabel = fxBibEpreuveDisplayName($epr, $strLangue);
|
||
$infoBib = fxInfosBibEpreuve($eprId);
|
||
?>
|
||
<div class="bib-global-epr" data-epr-id="<?php echo $eprId; ?>">
|
||
<label class="bib-global-epr__label">
|
||
<input type="checkbox"
|
||
class="bib-global-epr-select"
|
||
checked
|
||
data-epr-id="<?php echo $eprId; ?>">
|
||
<span class="bib-global-epr__name"><?php echo fxBibEsc($strLabel); ?></span>
|
||
<span class="bib-global-epr__pending text-muted small">
|
||
<?php echo fxBibEsc(fxBibMsg('bib_v4_global_batch_pending', (int)($infoBib['a_assigner'] ?? 0))); ?>
|
||
</span>
|
||
</label>
|
||
<div class="bib-global-epr__ranges">
|
||
<?php foreach ($item['ranges'] as $range) { ?>
|
||
<label class="bib-global-range__label">
|
||
<input type="checkbox"
|
||
class="bib-global-range-select"
|
||
checked
|
||
data-epr-id="<?php echo $eprId; ?>"
|
||
data-range-id="<?php echo (int)$range['epr_bib_id']; ?>">
|
||
<span><?php echo fxBibEsc(fxBibMsg(
|
||
'bib_v4_global_batch_range',
|
||
(int)$range['start'],
|
||
(int)$range['end'],
|
||
(int)$range['dispo']
|
||
)); ?></span>
|
||
</label>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
<?php } ?>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__order mb-2">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order', 1); ?></label>
|
||
<select class="form-control form-control-sm bib-global-batch-order">
|
||
<?php
|
||
$tabGlobalSort = fxBibGetSortOptionsForEpreuve(0, $int_eve_id, $strLangue, false, false);
|
||
echo fxBibRenderBatchSortOptions($tabGlobalSort, 'ba:2', false, $strLangue);
|
||
?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__order mb-2">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order_2', 1); ?></label>
|
||
<select class="form-control form-control-sm bib-global-batch-order-2">
|
||
<?php echo fxBibRenderBatchSortOptions($tabGlobalSort, '', true, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<p class="bib-global-batch__info text-muted small mb-2"></p>
|
||
|
||
<div class="epr-action-row">
|
||
<?php echo fxBibActionGroupOpen('epr-action-global-sim-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-simuler-global-batch">
|
||
<?php fxBibTexte('bib_v4_batch_simulate', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_simulate', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_simulate'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
<?php echo fxBibActionGroupOpen('epr-action-global-go-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-success btn-go-global-batch">
|
||
<?php fxBibTexte('bib_v4_batch_go', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_go', 'success', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_go'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
<?php }
|
||
|
||
echo fxBibGlobalBatchSectionClose();
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4443 — Bloc assignation sans séquence (création automatique de plages).
|
||
*/
|
||
function renderBibGlobalBatchPanelGenerated($int_eve_id, $tabEpreuves, $strLangue) {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$tabSolo = fxBibGetSoloEpreuvesWithoutSequence($int_eve_id, $tabEpreuves);
|
||
|
||
if (empty($tabSolo)) {
|
||
return '';
|
||
}
|
||
|
||
$tabGlobalSort = fxBibGetSortOptionsForEpreuve(0, $int_eve_id, $strLangue, false, false);
|
||
|
||
ob_start();
|
||
echo fxBibGlobalBatchSectionOpen('generated', 'bib_v4_global_batch_generated_title', $strLangue);
|
||
?>
|
||
<p class="bib-global-batch__hint text-muted small mb-2"><?php fxBibTexteTrad('bib_v4_global_batch_gen_hint', 1); ?></p>
|
||
<p class="bib-global-batch__team-note text-muted small mb-3"><?php fxBibTexteTrad('bib_v4_global_batch_team_note', 1); ?></p>
|
||
|
||
<div class="bib-global-batch__start-bib mb-3">
|
||
<label class="bib-global-batch__start-bib-label"><?php fxBibTexteAide('bib_v4_global_batch_start_bib', 1); ?></label>
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-global-gen-start-bib"
|
||
min="1"
|
||
step="1"
|
||
value="1"
|
||
inputmode="numeric"
|
||
placeholder="1">
|
||
</div>
|
||
|
||
<div class="bib-global-batch__epreuves">
|
||
<?php foreach ($tabSolo as $epr) {
|
||
$eprId = (int)$epr['epr_id'];
|
||
$strLabel = fxBibEpreuveDisplayName($epr, $strLangue);
|
||
$infoBib = fxInfosBibEpreuve($eprId);
|
||
$intPending = (int)($infoBib['a_assigner'] ?? 0);
|
||
$blnInactive = ($intPending <= 0);
|
||
?>
|
||
<div class="bib-global-epr<?php echo $blnInactive ? ' bib-global-epr--inactive' : ''; ?>"
|
||
data-epr-id="<?php echo $eprId; ?>"
|
||
data-pending="<?php echo $intPending; ?>">
|
||
<label class="bib-global-epr__label">
|
||
<input type="checkbox"
|
||
class="bib-global-gen-epr-select"
|
||
<?php echo $blnInactive ? 'disabled' : 'checked'; ?>
|
||
data-epr-id="<?php echo $eprId; ?>">
|
||
<span class="bib-global-epr__name"><?php echo fxBibEsc($strLabel); ?></span>
|
||
<span class="bib-global-epr__pending text-muted small">
|
||
<?php echo fxBibEsc(fxBibMsg('bib_v4_global_batch_pending', $intPending)); ?>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
<?php } ?>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__order mb-2">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order', 1); ?></label>
|
||
<select class="form-control form-control-sm bib-global-gen-batch-order">
|
||
<?php echo fxBibRenderBatchSortOptions($tabGlobalSort, 'ba:2', false, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__order mb-2">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order_2', 1); ?></label>
|
||
<select class="form-control form-control-sm bib-global-gen-batch-order-2">
|
||
<?php echo fxBibRenderBatchSortOptions($tabGlobalSort, '', true, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<p class="bib-global-batch__info bib-global-gen-batch__info text-muted small mb-2"></p>
|
||
|
||
<div class="epr-action-row">
|
||
<?php echo fxBibActionGroupOpen('epr-action-global-gen-sim-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-simuler-global-gen-batch">
|
||
<?php fxBibTexte('bib_v4_batch_simulate', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_simulate', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_simulate'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
<?php echo fxBibActionGroupOpen('epr-action-global-gen-go-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-success btn-go-global-gen-batch">
|
||
<?php fxBibTexte('bib_v4_batch_go', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_go', 'success', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_go'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
<?php
|
||
echo fxBibGlobalBatchSectionClose();
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4445 — Bloc assignation libre (Début/Qté/Fin, sans création de séquence).
|
||
* Liste toutes les épreuves solo, avec ou sans séquence existante.
|
||
*/
|
||
function renderBibGlobalBatchPanelFree($int_eve_id, $tabEpreuves, $strLangue) {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$tabSolo = fxBibGetSoloEpreuves($int_eve_id, $tabEpreuves);
|
||
|
||
if (empty($tabSolo)) {
|
||
return '';
|
||
}
|
||
|
||
$tabGlobalSort = fxBibGetSortOptionsForEpreuve(0, $int_eve_id, $strLangue, false, false);
|
||
|
||
ob_start();
|
||
echo fxBibGlobalBatchSectionOpen('free', 'bib_v4_global_batch_free_title', $strLangue);
|
||
?>
|
||
<p class="bib-global-batch__hint text-muted small mb-2"><?php fxBibTexteTrad('bib_v4_global_batch_free_hint', 1); ?></p>
|
||
<p class="bib-global-batch__team-note text-muted small mb-3"><?php fxBibTexteTrad('bib_v4_global_batch_team_note', 1); ?></p>
|
||
|
||
<div class="bib-global-free-range mb-3" data-range-pilot="">
|
||
<div class="bib-global-free-range__headers">
|
||
<div><?php echo fxBibColHeader('bib_v4_col_start'); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_qty'); ?></div>
|
||
<div class="bib-global-free-range__or" aria-hidden="true"><?php fxBibTexte('bib_v4_range_or', 1); ?></div>
|
||
<div><?php echo fxBibColHeader('bib_v4_col_end'); ?></div>
|
||
</div>
|
||
<div class="bib-global-free-range__fields">
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-global-free-start bib-field--active"
|
||
min="1"
|
||
step="1"
|
||
value=""
|
||
inputmode="numeric"
|
||
placeholder="">
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-global-free-qty bib-field--idle"
|
||
min="1"
|
||
step="1"
|
||
value=""
|
||
inputmode="numeric"
|
||
disabled>
|
||
<span class="bib-range-or bib-global-free-range__or" aria-hidden="true"><?php fxBibTexte('bib_v4_range_or', 1); ?></span>
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-global-free-end bib-field--idle"
|
||
min="1"
|
||
step="1"
|
||
value=""
|
||
inputmode="numeric"
|
||
disabled>
|
||
</div>
|
||
<div class="bib-global-free-range__feedback" aria-live="polite">
|
||
<p class="bib-global-free-range__qty mb-0"></p>
|
||
<p class="bib-global-free-range__dupes mb-0 bib-ui-hidden"></p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__epreuves">
|
||
<?php foreach ($tabSolo as $epr) {
|
||
$eprId = (int)$epr['epr_id'];
|
||
$strLabel = fxBibEpreuveDisplayName($epr, $strLangue);
|
||
$infoBib = fxInfosBibEpreuve($eprId);
|
||
$intPending = (int)($infoBib['a_assigner'] ?? 0);
|
||
$blnInactive = ($intPending <= 0);
|
||
?>
|
||
<div class="bib-global-epr<?php echo $blnInactive ? ' bib-global-epr--inactive' : ''; ?>"
|
||
data-epr-id="<?php echo $eprId; ?>"
|
||
data-pending="<?php echo $intPending; ?>">
|
||
<label class="bib-global-epr__label">
|
||
<input type="checkbox"
|
||
class="bib-global-free-epr-select"
|
||
<?php echo $blnInactive ? 'disabled' : 'checked'; ?>
|
||
data-epr-id="<?php echo $eprId; ?>">
|
||
<span class="bib-global-epr__name"><?php echo fxBibEsc($strLabel); ?></span>
|
||
<span class="bib-global-epr__pending text-muted small">
|
||
<?php echo fxBibEsc(fxBibMsg('bib_v4_global_batch_pending', $intPending)); ?>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
<?php } ?>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__order mb-2">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order', 1); ?></label>
|
||
<select class="form-control form-control-sm bib-global-free-batch-order">
|
||
<?php echo fxBibRenderBatchSortOptions($tabGlobalSort, 'ba:2', false, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="bib-global-batch__order mb-2">
|
||
<label><?php fxBibTexteAide('bib_v4_batch_order_2', 1); ?></label>
|
||
<select class="form-control form-control-sm bib-global-free-batch-order-2">
|
||
<?php echo fxBibRenderBatchSortOptions($tabGlobalSort, '', true, $strLangue); ?>
|
||
</select>
|
||
</div>
|
||
|
||
<p class="bib-global-batch__info bib-global-free-batch__info text-muted small mb-2"></p>
|
||
|
||
<div class="epr-action-row">
|
||
<?php echo fxBibActionGroupOpen('epr-action-global-free-sim-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-simuler-global-free-batch">
|
||
<?php fxBibTexte('bib_v4_batch_simulate', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_simulate', 'secondary', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_simulate'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
<?php echo fxBibActionGroupOpen('epr-action-global-free-go-group'); ?>
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-success btn-go-global-free-batch">
|
||
<?php fxBibTexte('bib_v4_batch_go', 1); ?>
|
||
</button>
|
||
<?php echo fxBibAideButton('bib_v4_batch_go', 'success', false); ?>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_batch_go'); ?>
|
||
<?php echo fxBibActionGroupClose(); ?>
|
||
</div>
|
||
<?php
|
||
echo fxBibGlobalBatchSectionClose();
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4436 / MSIN-4443 / MSIN-4445 — Panneau assignation globale (blocs indépendants).
|
||
* Appelé en AJAX à l'ouverture du panneau (pas au chargement page).
|
||
*/
|
||
function renderBibGlobalBatchPanel($int_eve_id, $tabEpreuves, $tabBibAssignments, $strLangue) {
|
||
$strExisting = renderBibGlobalBatchPanelExisting($int_eve_id, $tabEpreuves, $strLangue);
|
||
$strGenerated = renderBibGlobalBatchPanelGenerated($int_eve_id, $tabEpreuves, $strLangue);
|
||
$strFree = renderBibGlobalBatchPanelFree($int_eve_id, $tabEpreuves, $strLangue);
|
||
|
||
if ($strExisting === '' && $strGenerated === '' && $strFree === '') {
|
||
return '';
|
||
}
|
||
|
||
ob_start();
|
||
?>
|
||
<div id="bib-global-batch"
|
||
class="bib-global-batch bib-tool-panel"
|
||
data-bib-tool="global_batch"
|
||
data-global-batch-loaded="1">
|
||
<div class="bib-global-batch__body">
|
||
<?php
|
||
if ($strExisting !== '') {
|
||
echo $strExisting;
|
||
}
|
||
if ($strGenerated !== '') {
|
||
echo $strGenerated;
|
||
}
|
||
if ($strFree !== '') {
|
||
echo $strFree;
|
||
}
|
||
?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
function fxShowBibTool4($str_code, $int_eve_id, $strLangue){
|
||
global $objDatabase, $vDomaine;
|
||
|
||
$sqlEpreuves = "SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = " . intval($int_eve_id) . " AND epr_actif = 1 ORDER BY epr_id";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
|
||
$sqlBibAssignments = "SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri";
|
||
$tabBibAssignments = $objDatabase->fxGetResults($sqlBibAssignments);
|
||
|
||
?>
|
||
|
||
<?php
|
||
// MSIN-4470 — Retire le bandeau « Épreuves » sans masquer les badges d'inspection des permissions.
|
||
$strPermInspectBadges = '';
|
||
if (function_exists('fxEveAccesPermInspectBadge')) {
|
||
$strPermInspectBadges .= fxEveAccesPermInspectBadge('dossards.manage', 'bib');
|
||
$strPermInspectBadges .= fxEveAccesPermInspectBadge('epreuves.edit_qte', 'bib');
|
||
}
|
||
if (trim($strPermInspectBadges) !== '') {
|
||
echo '<div class="bib-tool-permission-inspect">' . $strPermInspectBadges . '</div>';
|
||
}
|
||
?>
|
||
|
||
<div id="module-bib" class="epr-wrapper" data-csrf-token="<?php echo fxBibEsc(fxBibCsrfToken()); ?>" data-lang="<?php echo fxBibEsc($strLangue); ?>" data-eve-id="<?php echo (int)$int_eve_id; ?>" data-allow-inter-epr="<?php echo fxBibEventAllowsInterEprDuplicates((int)$int_eve_id) ? '1' : '0'; ?>"<?php echo fxBibModuleJsDataAttrs(); ?><?php echo fxAdminTextEditModeActive() ? ' data-bib-trad="1"' : ''; ?>>
|
||
|
||
<?php echo renderBibToolNav((int)$int_eve_id, $tabEpreuves, $strLangue); ?>
|
||
|
||
<div id="bib-tool-store" class="bib-tool-store">
|
||
<div id="bib-event-config-mount">
|
||
<?php echo renderBibEventConfigPanel((int)$int_eve_id, $strLangue); ?>
|
||
</div>
|
||
|
||
<div id="bib-qty-summary-mount">
|
||
<?php echo renderBibQtySummaryPanelShell((int)$int_eve_id, $strLangue); ?>
|
||
</div>
|
||
|
||
<div id="bib-anomalies-mount">
|
||
<?php echo renderBibAnomaliesPanelShell((int)$int_eve_id, $strLangue); ?>
|
||
</div>
|
||
|
||
<div id="bib-dist-print-mount">
|
||
<?php echo renderBibDistPrintPanelShell((int)$int_eve_id, $strLangue); ?>
|
||
</div>
|
||
|
||
<?php echo renderBibGlobalBatchPanelShell((int)$int_eve_id, $tabEpreuves, $strLangue); ?>
|
||
</div>
|
||
|
||
<div id="bib-preparation-races" class="bib-preparation-races">
|
||
<?php for($i = 1; $i <= count($tabEpreuves); $i++){ ?>
|
||
|
||
<?php
|
||
$strClass = ($i & 1) ? '' : 'bg-light';
|
||
|
||
// $sqlBibRanges = "SELECT *
|
||
// FROM inscriptions_epreuves_bib
|
||
// WHERE epr_id = " . intval($tabEpreuves[$i]['epr_id']) . "
|
||
// ORDER BY epr_bib_start";
|
||
|
||
// $tabBibRanges = $objDatabase->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']);
|
||
$blnHasLockedRanges = fxBibEpreuveHasLockedRanges((int)$tabEpreuves[$i]['epr_id']);
|
||
$intSeqCount = fxBibCountSavedRanges($tabBibStats);
|
||
$intPending = (int)($infoBib['a_assigner'] ?? 0);
|
||
$tabQuantites = fxGetQuantites((int)$tabEpreuves[$i]['epr_id']);
|
||
$intPlacesAvailable = (int)($tabQuantites['qte_restante'] ?? 0);
|
||
// MSIN-4467 — Aucune épreuve ouverte au chargement; l'utilisateur choisit laquelle développer.
|
||
$blnRaceExpanded = false;
|
||
// MSIN-4467 — L'identité complète de l'épreuve reste visible dans son résumé replié.
|
||
$blnTeamEpreuve = ((int)$tabEpreuves[$i]['epr_equipe'] === 1);
|
||
$teamMode = (int)$tabEpreuves[$i]['epr_bib_team_mode'];
|
||
if ($teamMode <= 0) {
|
||
$teamMode = 1;
|
||
}
|
||
$lockTeamMode = ((int)$infoBib['avec_bib'] > 0);
|
||
$strEpreuveMode = $blnTeamEpreuve
|
||
? fxBibSiteOrBibTexte('promoteur_epr_equipe', 'bib_v4_summary_team')
|
||
: fxBibSiteOrBibTexte('promoteur_epr_solo', 'bib_v4_summary_solo');
|
||
$strTeamModeSummary = '';
|
||
if ($blnTeamEpreuve) {
|
||
$strTeamModeSummary = fxBibTexte(
|
||
$teamMode === 3 ? 'bib_v4_team_mode_one_team' : 'bib_v4_team_mode_individual',
|
||
0
|
||
);
|
||
}
|
||
|
||
?>
|
||
|
||
<?php /* MSIN-4379 — Étape 2 : attributs/data pour l'état auto au chargement de la page. */ ?>
|
||
<div class="epr-row <?php echo $strClass ?><?php echo $blnAutoActive ? ' auto-enabled' : ''; ?><?php echo $blnRaceExpanded ? ' is-expanded' : ''; ?>"
|
||
data-epr-id="<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>"
|
||
data-auto-active="<?php echo $blnAutoActive ? '1' : '0'; ?>"
|
||
data-auto-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_auto', 0)); ?>"
|
||
data-auto-label-config="<?php echo fxBibEsc(fxBibTexte('bib_v4_auto_config', 0)); ?>"
|
||
data-batch-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_assign_seq', 0)); ?>"
|
||
data-batch-label-cancel="<?php echo fxBibEsc(fxBibTexte('bib_v4_assign_seq_cancel', 0)); ?>"
|
||
data-reset-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_reset', 0)); ?>"
|
||
data-reset-cancel-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_reset_cancel', 0)); ?>"
|
||
data-go-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_batch_go', 0)); ?>"
|
||
data-bib-a-assigner="<?php echo (int)($infoBib['a_assigner'] ?? 0); ?>">
|
||
<div class="bib-race-summary"
|
||
role="button"
|
||
tabindex="0"
|
||
aria-expanded="<?php echo $blnRaceExpanded ? 'true' : 'false'; ?>"
|
||
aria-controls="bib-race-detail-<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>">
|
||
<div class="bib-race-summary__identity">
|
||
<div class="bib-race-summary__identity-head">
|
||
<strong><?php echo fxBibEsc(fxBibEpreuveDisplayName($tabEpreuves[$i], $strLangue)); ?></strong>
|
||
<?php echo fxBibRenderViewRangeButton(
|
||
(int)$tabEpreuves[$i]['epr_id'],
|
||
0,
|
||
'btn btn-sm btn-light bib-race-summary-view btn-view-range'
|
||
); ?>
|
||
</div>
|
||
<div class="bib-race-summary__metadata">
|
||
<span><?php echo fxBibEsc(trim($tabEpreuves[$i]['epr_nom_' . $strLangue] ?? '')); ?></span>
|
||
<span><?php echo fxBibEsc($strEpreuveMode); ?></span>
|
||
<?php if ($strTeamModeSummary !== '') { ?>
|
||
<span class="bib-race-summary-team-mode"><?php echo fxBibEsc($strTeamModeSummary); ?></span>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
<section class="bib-race-summary__group bib-race-summary__group--quantities">
|
||
<h4><?php fxBibTexteTrad('bib_v5_group_quantities', 1); ?></h4>
|
||
<dl class="bib-race-summary__stats">
|
||
<div>
|
||
<dd class="bib-race-summary-total bib-total"><?php echo (int)($infoBib['total'] ?? 0); ?></dd>
|
||
<dt><?php fxBibTexteTrad('bib_v5_stat_registered', 1); ?></dt>
|
||
</div>
|
||
<div>
|
||
<dd class="bib-race-summary-available"><?php echo $intPlacesAvailable; ?></dd>
|
||
<dt><?php echo fxBibEsc(fxBibSiteOrBibTexte('promoteur_qte_epr_qte', 'bib_v4_summary_dispo')); ?></dt>
|
||
</div>
|
||
</dl>
|
||
</section>
|
||
<section class="bib-race-summary__group bib-race-summary__group--bibs">
|
||
<h4><?php fxBibTexteTrad('bib_v5_group_bibs', 1); ?></h4>
|
||
<dl class="bib-race-summary__stats">
|
||
<div>
|
||
<dd class="bib-race-summary-assigned bib-avec"><?php echo (int)($infoBib['avec_bib'] ?? 0); ?></dd>
|
||
<dt><?php fxBibTexteTrad('bib_v5_stat_assigned', 1); ?></dt>
|
||
</div>
|
||
<div>
|
||
<dd class="bib-race-summary-ranges"><?php echo $intSeqCount; ?></dd>
|
||
<dt><?php fxBibTexteTrad('bib_v5_production_ranges', 1); ?></dt>
|
||
</div>
|
||
<div>
|
||
<dd class="bib-race-summary-pending"><?php echo $intPending; ?></dd>
|
||
<dt><?php fxBibTexteTrad('bib_v5_stat_pending', 1); ?></dt>
|
||
</div>
|
||
</dl>
|
||
</section>
|
||
<button type="button"
|
||
class="bib-race-toggle"
|
||
data-label-expand="<?php echo fxBibEsc(fxBibTexte('bib_v4_expand', 0)); ?>"
|
||
data-label-collapse="<?php echo fxBibEsc(fxBibTexte('bib_v4_collapse', 0)); ?>"
|
||
aria-label="<?php echo fxBibEsc(fxBibTexte($blnRaceExpanded ? 'bib_v4_collapse' : 'bib_v4_expand', 0)); ?>"
|
||
title="<?php echo fxBibEsc(fxBibTexte($blnRaceExpanded ? 'bib_v4_collapse' : 'bib_v4_expand', 0)); ?>">
|
||
<i class="fa <?php echo $blnRaceExpanded ? 'fa-chevron-up' : 'fa-chevron-down'; ?>" aria-hidden="true"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="epr-row-detail" id="bib-race-detail-<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>">
|
||
<div class="epr-col-right">
|
||
<?php if ($blnTeamEpreuve) { ?>
|
||
<section class="bib-team-mode-step">
|
||
<div class="team-mode-box"
|
||
data-epr-id="<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>">
|
||
<div class="team-mode-title">
|
||
<?php fxBibTexteTrad('bib_v4_team_mode_title', 1); ?>
|
||
</div>
|
||
<div class="bib-team-mode-options">
|
||
<label class="team-mode-option">
|
||
<input type="radio"
|
||
name="team_mode_<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>"
|
||
value="1"
|
||
<?php echo ($lockTeamMode ? 'disabled' : ''); ?>
|
||
<?php echo ($teamMode === 1 ? 'checked' : ''); ?>>
|
||
<span><?php fxBibTexteTrad('bib_v4_team_mode_individual', 1); ?></span>
|
||
</label>
|
||
<label class="team-mode-option">
|
||
<input type="radio"
|
||
name="team_mode_<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>"
|
||
value="3"
|
||
<?php echo ($lockTeamMode ? 'disabled' : ''); ?>
|
||
<?php echo ($teamMode === 3 ? 'checked' : ''); ?>>
|
||
<span><?php fxBibTexteTrad('bib_v4_team_mode_one_team', 1); ?></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php } ?>
|
||
|
||
<?php /* MSIN-4379 — Gestion des épreuves : quantités et paramètres (distinct de l'assignation de dossard). */ ?>
|
||
<div class="epr-block epr-block-gestion">
|
||
<div class="epr-header epr-header--collapsible">
|
||
<div class="epr-header-start">
|
||
<?php echo fxBibBlockHeader('bib_v5_quantities_title'); ?>
|
||
<span class="epr-header-summaries">
|
||
<?php echo fxBibGestionHeaderSummary((int)$tabEpreuves[$i]['epr_id']); ?>
|
||
</span>
|
||
</div>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, false); ?>
|
||
</div>
|
||
<div class="epr-content">
|
||
<?php echo renderBibGestionEpreuve((int)$tabEpreuves[$i]['epr_id'], (int)$int_eve_id, $strLangue); ?>
|
||
</div>
|
||
</div>
|
||
|
||
<?php /* MSIN-4379 — Assignation de dossard : séquences + actions (ex 3e colonne). */ ?>
|
||
<div class="epr-block epr-block-assign is-collapsed">
|
||
<div class="epr-header epr-header--collapsible">
|
||
<div class="epr-header-start">
|
||
<?php echo fxBibBlockHeader('bib_v5_bib_assignment_title', 'bib_v4_assign_doc'); ?>
|
||
<span class="epr-header-summaries">
|
||
<?php echo fxBibAssignHeaderSummary(fxBibCountSavedRanges($tabBibStats), $blnAutoActive); ?>
|
||
</span>
|
||
</div>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content">
|
||
<section class="bib-assignment-step">
|
||
<div class="bib-assignment-step__header">
|
||
<span class="bib-assignment-step__number" aria-hidden="true">1</span>
|
||
<div class="bib-assignment-step__heading">
|
||
<h3><?php fxBibTexteTrad('bib_v5_ranges_title', 1); ?></h3>
|
||
<p><?php fxBibTexteTrad('bib_v5_ranges_hint', 1); ?></p>
|
||
</div>
|
||
<div class="bib-assignment-step__actions">
|
||
<?php echo renderBibEpreuveResetAllButton(
|
||
(int)$tabEpreuves[$i]['epr_id'],
|
||
$infoBib,
|
||
$blnHasLockedRanges
|
||
); ?>
|
||
</div>
|
||
</div>
|
||
|
||
<?php if (count($tabBibStats) == 0) { ?>
|
||
|
||
<?php echo renderBibRanges([], $tabEpreuves[$i]['epr_id']); ?>
|
||
|
||
<?php } else { ?>
|
||
|
||
<?php echo renderBibRanges($tabBibStats, $tabEpreuves[$i]['epr_id']); ?>
|
||
|
||
<?php } ?>
|
||
</section>
|
||
|
||
<div class="epr-assign-divider" role="separator" aria-hidden="true"></div>
|
||
<section class="bib-assignment-step">
|
||
<div class="bib-assignment-step__header">
|
||
<span class="bib-assignment-step__number" aria-hidden="true">2</span>
|
||
<div>
|
||
<h3><?php fxBibTexteTrad('bib_v5_method_title', 1); ?></h3>
|
||
</div>
|
||
</div>
|
||
<?php echo renderBibAssignActions(
|
||
(int)$tabEpreuves[$i]['epr_id'],
|
||
(int)$int_eve_id,
|
||
$strLangue,
|
||
$infoBib,
|
||
$blnAutoActive,
|
||
(int)$tabEpreuves[$i]['epr_equipe'] === 1,
|
||
count($tabBibStats) > 0,
|
||
$tabEpreuves[$i]
|
||
); ?>
|
||
</section>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<?php } ?>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<?php echo fxDocRenderModule('bib_v4_assign_doc'); ?>
|
||
<?php echo fxDocRenderModule('bib_v4_dist_print_doc'); // MSIN-4471 ?>
|
||
|
||
<?php
|
||
}
|
||
/** MSIN-4379 — no_bib est stocké en texte : comparaison / tri / MAX numériques en SQL. */
|
||
function fxBibSqlNoBibUnsigned($strColumn = 'no_bib') {
|
||
$strColumn = preg_replace('/[^a-z0-9_.]/', '', $strColumn);
|
||
if ($strColumn === '') {
|
||
$strColumn = 'no_bib';
|
||
}
|
||
|
||
return "CAST(NULLIF(TRIM($strColumn), '') AS UNSIGNED)";
|
||
}
|
||
|
||
/**
|
||
* SQL — nombre d'unités partageant un no_bib pour une épreuve.
|
||
* Solo / équipe « dossards individuels » : une personne = une unité (COUNT participants).
|
||
* Équipe « 1 équipe = 1 dossard » (epr_bib_team_mode = 3) : une équipe = une unité (DISTINCT pec_id).
|
||
*/
|
||
function fxBibSqlDuplicateUnitCount($strEprIdExpr, $strBibNumExpr) {
|
||
$strBibP2 = fxBibSqlNoBibUnsigned('p2.no_bib');
|
||
$strTeamMode = "(SELECT CASE WHEN e.epr_equipe = 1 THEN IFNULL(NULLIF(e.epr_bib_team_mode, 0), 1) ELSE 1 END FROM inscriptions_epreuves e WHERE e.epr_id = ($strEprIdExpr) LIMIT 1)";
|
||
|
||
return "(CASE WHEN $strTeamMode = 3 THEN (
|
||
SELECT COUNT(DISTINCT IF(p2.pec_id > 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 rp.is_cancelled = 0
|
||
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 rp.is_cancelled = 0
|
||
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 rp.is_cancelled = 0
|
||
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 rp.is_cancelled = 0
|
||
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<int, array<string, mixed>>
|
||
*/
|
||
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-4424 — Dossards en double entre épreuves (même no_bib, epr_id distincts).
|
||
* Vide si le réglage événement autorise les doublons inter-épreuves.
|
||
*
|
||
* @return array<int, array<string, mixed>>
|
||
*/
|
||
function fxBibAnomalyInterEprDuplicateBibs($int_eve_id, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
|
||
if ($int_eve_id <= 0 || fxBibEventAllowsInterEprDuplicates($int_eve_id)) {
|
||
return [];
|
||
}
|
||
|
||
$sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib');
|
||
$sqlBibNumP2 = fxBibSqlNoBibUnsigned('p2.no_bib');
|
||
|
||
$sql = "
|
||
SELECT
|
||
$sqlBibNumP AS no_bib,
|
||
p.epr_id,
|
||
p.par_id,
|
||
p.par_prenom,
|
||
p.par_nom,
|
||
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 $sqlBibNumP IN (
|
||
SELECT $sqlBibNumP2
|
||
FROM resultats_participants p2
|
||
INNER JOIN inscriptions_epreuves e2 ON e2.epr_id = p2.epr_id
|
||
WHERE e2.eve_id = $int_eve_id
|
||
AND p2.is_cancelled = 0
|
||
AND $sqlBibNumP2 > 0
|
||
GROUP BY $sqlBibNumP2
|
||
HAVING COUNT(DISTINCT p2.epr_id) > 1
|
||
)
|
||
ORDER BY $sqlBibNumP, p.epr_id, p.par_nom, p.par_prenom
|
||
";
|
||
|
||
$rows = $objDatabase->fxGetResults($sql);
|
||
|
||
if (!is_array($rows) || empty($rows)) {
|
||
return [];
|
||
}
|
||
|
||
$grouped = [];
|
||
|
||
foreach ($rows as $row) {
|
||
$intBib = (int)$row['no_bib'];
|
||
$key = (string)$intBib;
|
||
|
||
if (!isset($grouped[$key])) {
|
||
$grouped[$key] = [
|
||
'no_bib' => $intBib,
|
||
'entries' => [],
|
||
];
|
||
}
|
||
|
||
$intEprId = (int)$row['epr_id'];
|
||
$strEprKey = (string)$intEprId;
|
||
|
||
if (!isset($grouped[$key]['entries'][$strEprKey])) {
|
||
$grouped[$key]['entries'][$strEprKey] = [
|
||
'epr_id' => $intEprId,
|
||
'epr_label' => fxBibAnomalyEprLabel($row, $strLangue),
|
||
'participants' => [],
|
||
];
|
||
}
|
||
|
||
$grouped[$key]['entries'][$strEprKey]['participants'][] = [
|
||
'par_id' => (int)$row['par_id'],
|
||
'par_prenom' => trim($row['par_prenom'] ?? ''),
|
||
'par_nom' => trim($row['par_nom'] ?? ''),
|
||
];
|
||
}
|
||
|
||
foreach ($grouped as &$item) {
|
||
$item['entries'] = array_values($item['entries']);
|
||
}
|
||
unset($item);
|
||
|
||
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<int, array<string, mixed>>
|
||
*/
|
||
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-4405 — Dossards orphelins : inscription annulée dont le no_bib occupe encore une séquence.
|
||
* Cause alignée sur fxGetAnnulationCause (annule / transfert), pas de collision inter-épreuves.
|
||
*
|
||
* @return array<int, array<string, mixed>>
|
||
*/
|
||
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.pec_id,
|
||
p.par_prenom,
|
||
p.par_nom,
|
||
ec.pec_actif
|
||
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.eve_id = e.eve_id
|
||
AND p.is_cancelled = 1
|
||
AND $sqlBibNumP > 0
|
||
AND $sqlBibNumP BETWEEN b.epr_bib_start AND b.epr_bib_finish
|
||
INNER JOIN resultats_epreuves_commandees ec
|
||
ON ec.pec_id_original = p.pec_id
|
||
AND ec.epr_id = b.epr_id
|
||
AND ec.is_cancelled = 1
|
||
WHERE e.eve_id = $int_eve_id
|
||
AND b.epr_bib_start IS NOT NULL
|
||
AND b.epr_bib_finish IS NOT NULL
|
||
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) {
|
||
$intPecId = (int)$row['pec_id'];
|
||
$strCause = fxGetAnnulationCause($intPecId, isset($row['pec_actif']) ? (int)$row['pec_actif'] : null);
|
||
|
||
$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_cause' => $strCause,
|
||
'par_id' => (int)$row['par_id'],
|
||
'pec_id' => $intPecId,
|
||
'par_prenom' => trim($row['par_prenom'] ?? ''),
|
||
'par_nom' => trim($row['par_nom'] ?? ''),
|
||
];
|
||
}
|
||
|
||
return $out;
|
||
}
|
||
|
||
/** MSIN-4405 — Clé i18n bib pour la cause d'orphelin (alignée fxGetAnnulationCause). */
|
||
function fxBibAnomalyOrphanCauseKey($strCause) {
|
||
$strCause = trim((string)$strCause);
|
||
if (!in_array($strCause, ['annule', 'transfert'], true)) {
|
||
$strCause = 'annule';
|
||
}
|
||
|
||
return 'bib_v4_anomalies_orphan_' . $strCause;
|
||
}
|
||
|
||
/**
|
||
* 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<int, array<string, mixed>>
|
||
*/
|
||
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<int, array<string, mixed>>
|
||
*/
|
||
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.pec_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'],
|
||
'pec_id' => (int)$row['pec_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),
|
||
'inter_epr_dupes' => fxBibAnomalyInterEprDuplicateBibs($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', 'inter_epr_dupes', 'out_of_range', 'orphans', 'auto_miss'] as $strKey) {
|
||
if (!empty($tabAnomalies[$strKey]) && is_array($tabAnomalies[$strKey])) {
|
||
$intTotal += count($tabAnomalies[$strKey]);
|
||
}
|
||
}
|
||
return $intTotal;
|
||
}
|
||
|
||
/** MSIN-4424 — Corps du panneau configuration globale (réglages événement). */
|
||
function renderBibEventConfigPanelContent($int_eve_id) {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$blnAllow = fxBibEventAllowsInterEprDuplicates($int_eve_id);
|
||
|
||
ob_start();
|
||
?>
|
||
<label class="bib-event-settings__label">
|
||
<input type="checkbox"
|
||
class="bib-event-allow-inter-epr"
|
||
value="1"
|
||
<?php echo $blnAllow ? ' checked' : ''; ?>>
|
||
<span class="bib-event-settings__text"><?php fxBibTexte('bib_v4_allow_inter_epr', 1); ?></span>
|
||
<?php echo fxBibAideButton('bib_v4_allow_inter_epr', '', false); ?>
|
||
</label>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4424 — Pastille en-tête quand l'option inter-épreuves est active. */
|
||
function renderBibEventConfigHeaderNote($blnAllow) {
|
||
$strLabel = fxBibTexte('bib_v4_event_config_inter_epr_on', 0);
|
||
|
||
return '<span class="epr-header-summary bib-event-config-note'
|
||
. fxBibUiHiddenClass((bool)$blnAllow)
|
||
. '" data-bib-inter-epr-note="1"'
|
||
. ' title="' . fxBibEsc(fxBibTexte('bib_v4_allow_inter_epr', 0)) . '">'
|
||
. fxBibEsc($strLabel)
|
||
. '</span>';
|
||
}
|
||
|
||
/** MSIN-4424 — Panneau repliable : configuration globale assignation dossards (événement). */
|
||
function renderBibEventConfigPanel($int_eve_id, $strLangue = 'fr') {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$blnAllow = fxBibEventAllowsInterEprDuplicates($int_eve_id);
|
||
|
||
ob_start();
|
||
?>
|
||
<div id="bib-event-config-panel"
|
||
class="bib-event-config-panel bib-anomalies-panel bib-tool-panel epr-block is-collapsed"
|
||
data-bib-tool="event_config"
|
||
data-eve-id="<?php echo $int_eve_id; ?>">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_event_config_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_event_config_title'); ?>
|
||
</span>
|
||
<span class="bib-event-config-header-actions">
|
||
<?php echo renderBibEventConfigHeaderNote($blnAllow); ?>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</span>
|
||
</div>
|
||
<div class="epr-content bib-event-config-content">
|
||
<?php echo renderBibEventConfigPanelContent($int_eve_id); ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4424 — Agrège les quantités dossards / inscriptions pour tout l'événement.
|
||
*
|
||
* @return array{totals: array<string, int>, epreuves: array<int, array<string, mixed>>}
|
||
*/
|
||
function fxBibCollectEventQtySummary($int_eve_id, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$tabTotals = [
|
||
'a_assigner' => 0,
|
||
'bib_restant' => 0,
|
||
'orphelins' => 0,
|
||
'total' => 0,
|
||
'avec_bib' => 0,
|
||
'sans_bib' => 0,
|
||
'places_dispo' => 0,
|
||
];
|
||
$tabEpreuvesRows = [];
|
||
|
||
if ($int_eve_id <= 0) {
|
||
return ['totals' => $tabTotals, 'epreuves' => $tabEpreuvesRows];
|
||
}
|
||
|
||
$sqlEpreuves = "
|
||
SELECT *
|
||
FROM inscriptions_epreuves
|
||
WHERE eve_id = $int_eve_id
|
||
AND epr_actif = 1
|
||
ORDER BY epr_id
|
||
";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
if (!is_array($tabEpreuves)) {
|
||
$tabEpreuves = [];
|
||
}
|
||
|
||
$tabOrphans = fxBibAnomalyOrphanBibs($int_eve_id, $strLangue);
|
||
$tabOrphansByEpr = [];
|
||
foreach ($tabOrphans as $item) {
|
||
$intEprId = (int)($item['epr_id'] ?? 0);
|
||
if ($intEprId > 0) {
|
||
$tabOrphansByEpr[$intEprId] = ($tabOrphansByEpr[$intEprId] ?? 0) + 1;
|
||
}
|
||
}
|
||
|
||
foreach ($tabEpreuves as $epr) {
|
||
$epr_id = (int)$epr['epr_id'];
|
||
$infoBib = fxInfosBibEpreuve($epr_id);
|
||
$arrQte = fxGetQuantites($epr_id);
|
||
|
||
$intBibRestant = 0;
|
||
$tabRanges = fxInfosBibRange($epr_id, 0, false);
|
||
if (is_array($tabRanges)) {
|
||
foreach ($tabRanges as $range) {
|
||
if (is_array($range)) {
|
||
$intBibRestant += fxBibRangeDispoFromRow($range);
|
||
}
|
||
}
|
||
}
|
||
|
||
$tabRow = [
|
||
'epr_id' => $epr_id,
|
||
'epr_label' => fxBibAnomalyEprLabel($epr, $strLangue),
|
||
'total' => (int)($infoBib['total'] ?? 0),
|
||
'avec_bib' => (int)($infoBib['avec_bib'] ?? 0),
|
||
'sans_bib' => (int)($infoBib['sans_bib'] ?? 0),
|
||
'a_assigner' => (int)($infoBib['a_assigner'] ?? 0),
|
||
'bib_restant' => $intBibRestant,
|
||
'orphelins' => (int)($tabOrphansByEpr[$epr_id] ?? 0),
|
||
'places_dispo' => (int)($arrQte['qte_restante'] ?? 0),
|
||
];
|
||
$tabEpreuvesRows[] = $tabRow;
|
||
|
||
$tabTotals['a_assigner'] += $tabRow['a_assigner'];
|
||
$tabTotals['bib_restant'] += $tabRow['bib_restant'];
|
||
$tabTotals['total'] += $tabRow['total'];
|
||
$tabTotals['avec_bib'] += $tabRow['avec_bib'];
|
||
$tabTotals['sans_bib'] += $tabRow['sans_bib'];
|
||
$tabTotals['places_dispo'] += $tabRow['places_dispo'];
|
||
}
|
||
|
||
$tabTotals['orphelins'] = count($tabOrphans);
|
||
|
||
return ['totals' => $tabTotals, 'epreuves' => $tabEpreuvesRows];
|
||
}
|
||
|
||
/** MSIN-4424 — Coquille sommaire quantités (détail chargé à la première ouverture). */
|
||
function renderBibQtySummaryPanelShell($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();
|
||
?>
|
||
<div id="bib-qty-summary-panel"
|
||
class="bib-qty-summary-panel bib-anomalies-panel bib-tool-panel epr-block is-collapsed"
|
||
data-bib-tool="qty_summary"
|
||
data-eve-id="<?php echo $int_eve_id; ?>"
|
||
data-bib-qty-summary-deferred="1">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_qty_summary_title'); ?>
|
||
<span class="bib-qty-summary-badges bib-qty-summary-badges--pending" aria-hidden="true">…</span>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-qty-summary-content">
|
||
<div class="ms1-loader ms1-loader--inline" role="status" aria-live="polite" aria-busy="true">
|
||
<img class="ms1-loader__runner"
|
||
src="<?php echo fxBibEsc($strRunnerSrc); ?>"
|
||
alt=""
|
||
role="presentation"
|
||
decoding="async">
|
||
<span class="ms1-loader__label"><?php echo fxBibEsc($strWait); ?></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4424 — Panneau sommaire des quantités (HTML). */
|
||
function renderBibQtySummaryPanel($int_eve_id, $strLangue = 'fr', $tabSummary = null) {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($tabSummary === null) {
|
||
$tabSummary = fxBibCollectEventQtySummary($int_eve_id, $strLangue);
|
||
}
|
||
|
||
$tabTotals = $tabSummary['totals'] ?? [];
|
||
$tabEpreuves = $tabSummary['epreuves'] ?? [];
|
||
$blnHasSansBib = (int)($tabTotals['sans_bib'] ?? 0) > 0;
|
||
$blnHasOrphans = (int)($tabTotals['orphelins'] ?? 0) > 0;
|
||
|
||
ob_start();
|
||
?>
|
||
<div id="bib-qty-summary-panel"
|
||
class="bib-qty-summary-panel bib-anomalies-panel bib-tool-panel epr-block<?php echo ($blnHasSansBib || $blnHasOrphans) ? ' bib-qty-summary-panel--alert' : ''; ?> is-collapsed"
|
||
data-bib-tool="qty_summary"
|
||
data-eve-id="<?php echo $int_eve_id; ?>"
|
||
data-bib-qty-summary-loaded="1">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_qty_summary_title'); ?>
|
||
<span class="bib-qty-summary-badges">
|
||
<span class="epr-header-summary bib-qty-summary-badge">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_total', 0)); ?> :
|
||
<strong><?php echo (int)($tabTotals['total'] ?? 0); ?></strong>
|
||
</span>
|
||
<span class="epr-header-summary epr-header-summary--dispo bib-qty-summary-badge">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_places_dispo', 0)); ?> :
|
||
<strong><?php echo (int)($tabTotals['places_dispo'] ?? 0); ?></strong>
|
||
</span>
|
||
<span class="epr-header-summary bib-qty-summary-badge">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_avec_bib', 0)); ?> :
|
||
<strong><?php echo (int)($tabTotals['avec_bib'] ?? 0); ?></strong>
|
||
</span>
|
||
<span class="epr-header-summary epr-header-summary--bib bib-qty-summary-badge<?php echo $blnHasSansBib ? ' bib-qty-summary-badge--warn' : ''; ?>">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_sans_bib', 0)); ?> :
|
||
<strong><?php echo (int)($tabTotals['sans_bib'] ?? 0); ?></strong>
|
||
</span>
|
||
<span class="epr-header-summary bib-qty-summary-badge<?php echo $blnHasOrphans ? ' bib-qty-summary-badge--warn' : ''; ?>">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_orphelins', 0)); ?> :
|
||
<strong><?php echo (int)($tabTotals['orphelins'] ?? 0); ?></strong>
|
||
</span>
|
||
<span class="epr-header-summary bib-qty-summary-badge">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_bib_restant', 0)); ?> :
|
||
<strong><?php echo (int)($tabTotals['bib_restant'] ?? 0); ?></strong>
|
||
</span>
|
||
</span>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-qty-summary-content">
|
||
<section class="bib-qty-summary-totals" aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_qty_summary_global', 0)); ?>">
|
||
<h3 class="bib-qty-summary-section-title"><?php fxBibTexteTrad('bib_v4_qty_summary_global', 1); ?></h3>
|
||
<dl class="bib-qty-summary-dl">
|
||
<div class="bib-qty-summary-dl__row">
|
||
<dt><?php fxBibTexteTrad('bib_v4_qty_summary_total', 1); ?></dt>
|
||
<dd><?php echo (int)($tabTotals['total'] ?? 0); ?></dd>
|
||
</div>
|
||
<div class="bib-qty-summary-dl__row">
|
||
<dt><?php fxBibTexteTrad('bib_v4_qty_summary_places_dispo', 1); ?></dt>
|
||
<dd><?php echo (int)($tabTotals['places_dispo'] ?? 0); ?></dd>
|
||
</div>
|
||
<div class="bib-qty-summary-dl__row">
|
||
<dt><?php fxBibTexteTrad('bib_v4_qty_summary_avec_bib', 1); ?></dt>
|
||
<dd><?php echo (int)($tabTotals['avec_bib'] ?? 0); ?></dd>
|
||
</div>
|
||
<div class="bib-qty-summary-dl__row">
|
||
<dt><?php fxBibTexteTrad('bib_v4_qty_summary_sans_bib', 1); ?></dt>
|
||
<dd><?php echo (int)($tabTotals['sans_bib'] ?? 0); ?></dd>
|
||
</div>
|
||
<div class="bib-qty-summary-dl__row">
|
||
<dt><?php fxBibTexteTrad('bib_v4_qty_summary_orphelins', 1); ?></dt>
|
||
<dd><?php echo (int)($tabTotals['orphelins'] ?? 0); ?></dd>
|
||
</div>
|
||
<div class="bib-qty-summary-dl__row">
|
||
<dt><?php fxBibTexteTrad('bib_v4_qty_summary_bib_restant', 1); ?></dt>
|
||
<dd><?php echo (int)($tabTotals['bib_restant'] ?? 0); ?></dd>
|
||
</div>
|
||
</dl>
|
||
</section>
|
||
|
||
<?php if (!empty($tabEpreuves)) { ?>
|
||
<section class="bib-qty-summary-by-epr">
|
||
<h3 class="bib-qty-summary-section-title"><?php fxBibTexteTrad('bib_v4_qty_summary_by_epr', 1); ?></h3>
|
||
<div class="table-responsive">
|
||
<table class="table table-sm table-bordered bib-qty-summary-table mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th scope="col"><?php fxBibTexteTrad('bib_v4_qty_summary_col_epr', 1); ?></th>
|
||
<th scope="col" class="text-right"><?php fxBibTexteTrad('bib_v4_qty_summary_total', 1); ?></th>
|
||
<th scope="col" class="text-right"><?php fxBibTexteTrad('bib_v4_qty_summary_places_dispo', 1); ?></th>
|
||
<th scope="col" class="text-right"><?php fxBibTexteTrad('bib_v4_qty_summary_avec_bib', 1); ?></th>
|
||
<th scope="col" class="text-right"><?php fxBibTexteTrad('bib_v4_qty_summary_sans_bib', 1); ?></th>
|
||
<th scope="col" class="text-right"><?php fxBibTexteTrad('bib_v4_qty_summary_orphelins', 1); ?></th>
|
||
<th scope="col" class="text-right"><?php fxBibTexteTrad('bib_v4_qty_summary_bib_restant', 1); ?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($tabEpreuves as $row) { ?>
|
||
<tr>
|
||
<th scope="row"><?php echo fxBibEsc($row['epr_label'] ?? ''); ?></th>
|
||
<td class="text-right"><?php echo (int)($row['total'] ?? 0); ?></td>
|
||
<td class="text-right"><?php echo (int)($row['places_dispo'] ?? 0); ?></td>
|
||
<td class="text-right"><?php echo (int)($row['avec_bib'] ?? 0); ?></td>
|
||
<td class="text-right"><?php echo (int)($row['sans_bib'] ?? 0); ?></td>
|
||
<td class="text-right"><?php echo (int)($row['orphelins'] ?? 0); ?></td>
|
||
<td class="text-right"><?php echo (int)($row['bib_restant'] ?? 0); ?></td>
|
||
</tr>
|
||
<?php } ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4436 — Chemin relatif de retour vers la page gestion dossards (avec focus optionnel).
|
||
*/
|
||
function fxBibGestionEpreuvesReturnPath($int_eve_id, $strLangue = 'fr', $strFocus = '') {
|
||
$strBase = ($strLangue === 'fr')
|
||
? '/compte/inc_tableau_gestion_epreuves'
|
||
: '/account/inc_tableau_gestion_epreuves';
|
||
|
||
$strPath = $strBase
|
||
. '?promoteur_eve_id=' . rawurlencode(base64_encode((string)(int)$int_eve_id))
|
||
. '&lng=' . rawurlencode($strLangue);
|
||
|
||
if ($strFocus !== '') {
|
||
$strPath .= '&bib_focus=' . rawurlencode($strFocus);
|
||
}
|
||
|
||
return $strPath;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4436 — URL fiche gestion inscriptions v2 pour une anomalie dossard.
|
||
* Réutilise fxInscrGestionBuildUrl (même lien que la liste des inscriptions).
|
||
*/
|
||
function fxBibAnomalyInscrGestionUrl($int_eve_id, $int_pec_id, $strLangue = 'fr') {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$int_pec_id = (int)$int_pec_id;
|
||
|
||
if ($int_eve_id <= 0 || $int_pec_id <= 0) {
|
||
return '';
|
||
}
|
||
|
||
if (!function_exists('fxInscrGestionCanAccess')) {
|
||
require_once __DIR__ . '/inc_fx_inscriptions_gestion.php';
|
||
}
|
||
|
||
$intComId = isset($_SESSION['com_id']) ? (int)$_SESSION['com_id'] : 0;
|
||
if ($intComId <= 0 || !fxInscrGestionCanAccess($intComId, $int_eve_id)) {
|
||
return '';
|
||
}
|
||
|
||
$strReturn = fxInscrGestionEncodeReturnUrl(
|
||
fxBibGestionEpreuvesReturnPath($int_eve_id, $strLangue, 'anomalies')
|
||
);
|
||
|
||
return fxInscrGestionBuildUrl(
|
||
fxInscrGestionBaseUrl($strLangue, false),
|
||
$int_eve_id,
|
||
fxInscrGestionEmptyListRequest(),
|
||
[
|
||
'pec_id' => $int_pec_id,
|
||
'lng' => $strLangue,
|
||
'inscr_return' => $strReturn,
|
||
]
|
||
);
|
||
}
|
||
|
||
/** MSIN-4436 — Lien « voir l'inscription » (gestion inscriptions v2). */
|
||
function fxBibAnomalyRenderInscrLink($int_eve_id, $int_pec_id, $strLangue = 'fr') {
|
||
$strUrl = fxBibAnomalyInscrGestionUrl($int_eve_id, $int_pec_id, $strLangue);
|
||
if ($strUrl === '') {
|
||
return '';
|
||
}
|
||
|
||
$strLabel = fxBibTexte('bib_v4_anomalies_view_inscription', 0);
|
||
if ($strLabel === '' || $strLabel === 'bib_v4_anomalies_view_inscription') {
|
||
$strLabel = ($strLangue === 'en') ? 'View registration' : "Voir l'inscription";
|
||
}
|
||
|
||
return '<a class="bib-anomaly-inscr-link" href="' . fxBibEsc($strUrl) . '">'
|
||
. fxBibEsc($strLabel) . '</a>';
|
||
}
|
||
|
||
/**
|
||
* 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();
|
||
?>
|
||
<div id="bib-anomalies-panel"
|
||
class="bib-anomalies-panel bib-tool-panel epr-block is-collapsed"
|
||
data-bib-tool="anomalies"
|
||
data-eve-id="<?php echo $int_eve_id; ?>"
|
||
data-bib-anomalies-deferred="1">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_anomalies_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_anomalies_title'); ?>
|
||
<span class="bib-anomalies-count badge badge-secondary" aria-busy="true">…</span>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-anomalies-content">
|
||
<div class="ms1-loader ms1-loader--inline" role="status" aria-live="polite" aria-busy="true">
|
||
<img class="ms1-loader__runner"
|
||
src="<?php echo fxBibEsc($strRunnerSrc); ?>"
|
||
alt=""
|
||
role="presentation"
|
||
decoding="async">
|
||
<span class="ms1-loader__label"><?php echo fxBibEsc($strWait); ?></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4379 — Ouverture section anomalies repliable (fermée par défaut). */
|
||
function fxBibAnomalySectionOpen($strVariant, $strTitleClef, $intCount, $strLangue = 'fr') {
|
||
$strVariant = preg_replace('/[^a-z0-9-]/', '', (string)$strVariant);
|
||
?>
|
||
<section class="bib-anomaly-block bib-anomaly-block--<?php echo fxBibEsc($strVariant); ?> is-collapsed">
|
||
<div class="bib-anomaly-block-header epr-header epr-header--collapsible" role="button" tabindex="0"
|
||
aria-expanded="false">
|
||
<span class="epr-header-label bib-anomaly-block-header-label">
|
||
<?php fxBibTexte($strTitleClef, 1); ?>
|
||
<?php echo fxBibAideButton($strTitleClef); ?>
|
||
<span class="epr-header-summary bib-anomaly-block-count"><?php echo (int)$intCount; ?></span>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="bib-anomaly-block-content">
|
||
<?php
|
||
}
|
||
|
||
/** MSIN-4379 — Fermeture section anomalies repliable. */
|
||
function fxBibAnomalySectionClose() {
|
||
?>
|
||
</div>
|
||
</section>
|
||
<?php
|
||
}
|
||
|
||
/** MSIN-4379 — Panneau dashboard anomalies (HTML). */
|
||
function renderBibAnomaliesPanel($int_eve_id, $strLangue = 'fr', $tabAnomalies = null) {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($tabAnomalies === null) {
|
||
$tabAnomalies = fxBibCollectAnomalies($int_eve_id, $strLangue);
|
||
}
|
||
|
||
$intCount = fxBibAnomalyTotalCount($tabAnomalies);
|
||
$blnHasIssues = $intCount > 0;
|
||
|
||
ob_start();
|
||
?>
|
||
<div id="bib-anomalies-panel"
|
||
class="bib-anomalies-panel bib-tool-panel epr-block<?php echo $blnHasIssues ? ' bib-anomalies-panel--alert' : ''; ?> is-collapsed"
|
||
data-bib-tool="anomalies"
|
||
data-eve-id="<?php echo $int_eve_id; ?>">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_anomalies_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_anomalies_title'); ?>
|
||
<span class="bib-anomalies-count badge<?php echo $blnHasIssues ? ' badge-danger' : ' badge-success'; ?>">
|
||
<?php echo (int)$intCount; ?>
|
||
</span>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-anomalies-content">
|
||
<?php if (!$blnHasIssues) { ?>
|
||
<p class="bib-anomalies-empty text-muted mb-0">
|
||
<?php fxBibTexteTrad('bib_v4_anomalies_none', 1); ?>
|
||
</p>
|
||
<?php } else { ?>
|
||
<?php if (!empty($tabAnomalies['dupes'])) {
|
||
fxBibAnomalySectionOpen('dupes', 'bib_v4_anomalies_dupes_title', count($tabAnomalies['dupes']), $strLangue);
|
||
?>
|
||
<ul class="bib-anomaly-list list-unstyled mb-0">
|
||
<?php foreach ($tabAnomalies['dupes'] as $item) { ?>
|
||
<li class="bib-anomaly-item">
|
||
<strong><?php echo fxBibEsc($item['epr_label']); ?></strong>
|
||
—
|
||
<?php if ((int)$item['range_start'] > 0 || (int)$item['range_end'] > 0) { ?>
|
||
<?php echo fxBibMsgTrad(
|
||
'bib_v4_anomalies_range_fmt',
|
||
(int)$item['range_start'],
|
||
(int)$item['range_end']
|
||
); ?>
|
||
—
|
||
<?php } else { ?>
|
||
<?php fxBibTexteTrad('bib_v4_anomalies_no_range', 1); ?>
|
||
—
|
||
<?php } ?>
|
||
<?php echo fxBibMsgTrad(
|
||
'bib_v4_anomalies_bib_fmt',
|
||
(int)$item['no_bib']
|
||
); ?>
|
||
<ul class="bib-anomaly-sublist list-unstyled mb-0">
|
||
<?php foreach ($item['participants'] as $p) { ?>
|
||
<li><?php echo fxBibEsc(trim($p['par_prenom'] . ' ' . $p['par_nom'])); ?></li>
|
||
<?php } ?>
|
||
</ul>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php
|
||
fxBibAnomalySectionClose();
|
||
} ?>
|
||
|
||
<?php if (!empty($tabAnomalies['inter_epr_dupes'])) {
|
||
fxBibAnomalySectionOpen('inter-epr-dupes', 'bib_v4_anomalies_inter_epr_dupes_title', count($tabAnomalies['inter_epr_dupes']), $strLangue);
|
||
?>
|
||
<ul class="bib-anomaly-list list-unstyled mb-0">
|
||
<?php foreach ($tabAnomalies['inter_epr_dupes'] as $item) { ?>
|
||
<li class="bib-anomaly-item">
|
||
<?php echo fxBibMsgTrad('bib_v4_anomalies_bib_fmt', (int)$item['no_bib']); ?>
|
||
<ul class="bib-anomaly-sublist list-unstyled mb-0">
|
||
<?php foreach ($item['entries'] as $entry) { ?>
|
||
<li>
|
||
<strong><?php echo fxBibEsc($entry['epr_label']); ?></strong>
|
||
<ul class="bib-anomaly-sublist list-unstyled mb-0">
|
||
<?php foreach ($entry['participants'] as $p) { ?>
|
||
<li><?php echo fxBibEsc(trim($p['par_prenom'] . ' ' . $p['par_nom'])); ?></li>
|
||
<?php } ?>
|
||
</ul>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php
|
||
fxBibAnomalySectionClose();
|
||
} ?>
|
||
|
||
<?php if (!empty($tabAnomalies['out_of_range'])) {
|
||
fxBibAnomalySectionOpen('out-of-range', 'bib_v4_anomalies_out_of_range_title', count($tabAnomalies['out_of_range']), $strLangue);
|
||
?>
|
||
<ul class="bib-anomaly-list list-unstyled mb-0">
|
||
<?php foreach ($tabAnomalies['out_of_range'] as $item) { ?>
|
||
<li class="bib-anomaly-item">
|
||
<strong><?php echo fxBibEsc($item['epr_label']); ?></strong>
|
||
— <?php echo fxBibMsgTrad(
|
||
'bib_v4_anomalies_bib_fmt',
|
||
(int)$item['no_bib']
|
||
); ?>
|
||
<div class="bib-anomaly-detail text-muted small bib-anomaly-detail--split">
|
||
<span class="bib-anomaly-detail__meta">
|
||
<?php echo fxBibEsc(trim($item['par_prenom'] . ' ' . $item['par_nom'])); ?>
|
||
</span>
|
||
<?php echo fxBibAnomalyRenderInscrLink($int_eve_id, (int)($item['pec_id'] ?? 0), $strLangue); ?>
|
||
</div>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php
|
||
fxBibAnomalySectionClose();
|
||
} ?>
|
||
|
||
<?php if (!empty($tabAnomalies['orphans'])) {
|
||
fxBibAnomalySectionOpen('orphans', 'bib_v4_anomalies_orphans_title', count($tabAnomalies['orphans']), $strLangue);
|
||
?>
|
||
<ul class="bib-anomaly-list list-unstyled mb-0">
|
||
<?php foreach ($tabAnomalies['orphans'] as $item) {
|
||
$strTypeKey = fxBibAnomalyOrphanCauseKey($item['orphan_cause'] ?? 'annule');
|
||
?>
|
||
<li class="bib-anomaly-item">
|
||
<strong><?php echo fxBibEsc($item['epr_label']); ?></strong>
|
||
— <?php echo fxBibMsgTrad(
|
||
'bib_v4_anomalies_range_fmt',
|
||
(int)$item['range_start'],
|
||
(int)$item['range_end']
|
||
); ?>
|
||
— <?php echo fxBibMsgTrad(
|
||
'bib_v4_anomalies_bib_fmt',
|
||
(int)$item['no_bib']
|
||
); ?>
|
||
<div class="bib-anomaly-detail text-muted small bib-anomaly-detail--split">
|
||
<span class="bib-anomaly-detail__meta">
|
||
<?php echo fxBibEsc(trim($item['par_prenom'] . ' ' . $item['par_nom'])); ?>
|
||
— <?php fxBibTexteTrad($strTypeKey, 1); ?>
|
||
</span>
|
||
<?php echo fxBibAnomalyRenderInscrLink($int_eve_id, (int)($item['pec_id'] ?? 0), $strLangue); ?>
|
||
</div>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php
|
||
fxBibAnomalySectionClose();
|
||
} ?>
|
||
|
||
<?php if (!empty($tabAnomalies['auto_miss'])) {
|
||
fxBibAnomalySectionOpen('auto-miss', 'bib_v4_anomalies_auto_miss_title', count($tabAnomalies['auto_miss']), $strLangue);
|
||
?>
|
||
<ul class="bib-anomaly-list list-unstyled mb-0">
|
||
<?php foreach ($tabAnomalies['auto_miss'] as $item) { ?>
|
||
<li class="bib-anomaly-item">
|
||
<strong><?php echo fxBibEsc($item['epr_label']); ?></strong>
|
||
— <?php echo fxBibEsc(trim($item['par_prenom'] . ' ' . $item['par_nom'])); ?>
|
||
<?php if ($item['no_commande'] !== '') { ?>
|
||
— <?php echo fxBibMsgTrad('bib_v4_anomalies_order_fmt', $item['no_commande']); ?>
|
||
<?php } ?>
|
||
<div class="bib-anomaly-detail">
|
||
<button type="button"
|
||
class="btn btn-sm btn-primary bib-anomaly-goto-assign"
|
||
data-epr-id="<?php echo (int)$item['epr_id']; ?>"
|
||
data-par-id="<?php echo (int)$item['par_id']; ?>">
|
||
<?php fxBibTexteTrad('bib_v4_anomalies_assign_link', 1); ?>
|
||
</button>
|
||
</div>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php
|
||
fxBibAnomalySectionClose();
|
||
} ?>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* MSIN-4379 — Étape 2
|
||
* Indique si l'assignation automatique est active pour une épreuve
|
||
* (au moins une ligne epr_bib_auto = 1 dans inscriptions_epreuves_bib).
|
||
* Prochain tour : étape 6–7 (lecture de ce flag à l'inscription).
|
||
*/
|
||
function fxIsBibAutoActive($epr_id) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = intval($epr_id);
|
||
|
||
if ($epr_id <= 0) {
|
||
return false;
|
||
}
|
||
|
||
$sql = "
|
||
SELECT COUNT(*)
|
||
FROM inscriptions_epreuves_bib
|
||
WHERE epr_id = $epr_id
|
||
AND epr_bib_auto = 1
|
||
AND epr_bib_locked = 0
|
||
";
|
||
|
||
return (int)$objDatabase->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')];
|
||
}
|
||
|
||
if (fxBibProductionEpreuveIsLocked($epr_id)) {
|
||
return ['success' => false, 'message' => fxBibMsg('bib_v5_production_locked_error')];
|
||
}
|
||
|
||
$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 / MSIN-4455
|
||
* Assigne un dossard à un participant à l'achat (pools epr_bib_auto = 1).
|
||
* Même chemin anti-doublon que le batch : fxLoadUsedBibsForBatch + fxTryAssignNextBibForParticipant.
|
||
*/
|
||
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;
|
||
|
||
// Mode équipe 3 : reprendre le dossard déjà posé sur un coéquipier.
|
||
if ($isTeamEvent && $teamMode === 3 && $teamKey > 0) {
|
||
$existingBib = fxGetExistingTeamBibInDb($epr_id, $teamKey);
|
||
|
||
if ($existingBib !== null && (int)$existingBib > 0) {
|
||
$foundBib = (int)$existingBib;
|
||
$teamNumber = $foundBib;
|
||
|
||
if (fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib) <= 0) {
|
||
return ['success' => false, 'message' => 'assignation équipe impossible'];
|
||
}
|
||
}
|
||
}
|
||
|
||
// MSIN-4455 — Charger les numéros déjà pris + relecture BD avant UPDATE (comme le batch GO).
|
||
if ($foundBib === null) {
|
||
$usedBib = fxLoadUsedBibsForBatch($epr_id);
|
||
$findTeamMode = $isTeamEvent ? $teamMode : 1;
|
||
$foundBib = fxTryAssignNextBibForParticipant(
|
||
$epr_id,
|
||
$par_id,
|
||
$tabRanges,
|
||
'execute',
|
||
$usedBib,
|
||
$findTeamMode
|
||
);
|
||
}
|
||
|
||
if ($foundBib === null) {
|
||
if (function_exists('fxcreer_log')) {
|
||
fxcreer_log('MSIN-4455: 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'];
|
||
}
|
||
|
||
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)
|
||
];
|
||
|
||
if ($tabEpreuve && (int)$tabEpreuve['epr_equipe'] === 1) {
|
||
$info['nb_equipes'] = fxBibCountEquipes($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'];
|
||
}
|
||
|
||
$blnProductionLocked = fxBibProductionEpreuveIsLocked((int)$epr_id);
|
||
|
||
ob_start();
|
||
?>
|
||
|
||
|
||
|
||
<!-- HEADER -->
|
||
|
||
|
||
<div class="epr-table bib-container">
|
||
|
||
<?php if (count($tabBibRanges) > 0) { ?>
|
||
<?php /* MSIN-4379 — En-tête par épreuve ; visible dès qu'il y a ≥ 1 séquence (create AJAX inclus). */ ?>
|
||
<?php echo renderBibRangeHeader(); ?>
|
||
<?php } ?>
|
||
|
||
<?php
|
||
|
||
foreach ($tabBibRanges as $range) {
|
||
|
||
$start = (int)($range['epr_bib_start'] ?? 0);
|
||
$end = (int)($range['epr_bib_finish'] ?? 0);
|
||
|
||
$last = (isset($range['dernier_bib']) && is_numeric($range['dernier_bib']))
|
||
? (int)$range['dernier_bib']
|
||
: 0;
|
||
|
||
// =====================
|
||
// DISPO POUR ASSIGNATION (SANS TROUS AVANT)
|
||
// =====================
|
||
$nb_total = (int)($range['nb_total_range'] ?? 0);
|
||
$nb_utilises = (int)($range['nb_utilises'] ?? 0);
|
||
|
||
$mem_dispo = max(0, $nb_total - $nb_utilises);
|
||
|
||
$blnRangeLocked = fxBibRangeIsLocked($range);
|
||
$blnRangeEditLocked = $blnRangeLocked || $blnProductionLocked;
|
||
$tabSpec = fxBibRangeSpecValues($range);
|
||
|
||
|
||
?>
|
||
|
||
<div class="bib-range epr-line<?php echo $blnRangeEditLocked ? ' bib-range--locked' : ''; ?>"
|
||
data-id="<?php echo $range['epr_bib_id']; ?>"
|
||
data-locked="<?php echo $blnRangeEditLocked ? '1' : '0'; ?>"
|
||
data-user-locked="<?php echo $blnRangeLocked ? '1' : '0'; ?>"
|
||
data-production-locked="<?php echo $blnProductionLocked ? '1' : '0'; ?>"
|
||
data-has-values="<?php echo $tabSpec['has_values'] ? '1' : '0'; ?>">
|
||
|
||
<?php echo fxBibRenderRangeLockButton($range, $epr_id, $blnProductionLocked); ?>
|
||
<?php echo fxBibRenderProductionRangeLock($blnProductionLocked); ?>
|
||
|
||
<?php if ((int)$range['epr_bib_id'] > 0) { ?>
|
||
<?php echo fxBibRenderViewRangeButton((int)$epr_id, (int)$range['epr_bib_id']); ?>
|
||
<?php } else { ?>
|
||
<div></div>
|
||
<?php } ?>
|
||
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-start"
|
||
min="1"
|
||
value="<?php echo $range['epr_bib_start']; ?>"
|
||
placeholder="<?php echo fxBibEsc(fxBibTexte('bib_v4_range_start_ph', 0)); ?>"
|
||
<?php echo $blnRangeEditLocked ? 'readonly' : ''; ?>
|
||
<?php echo fxBibAideTippyAttr('bib_v4_col_start'); ?>>
|
||
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-qty"
|
||
min="1"
|
||
value="<?php echo ($tabSpec['qty'] !== '') ? (int)$tabSpec['qty'] : ''; ?>"
|
||
placeholder="<?php echo fxBibEsc(fxBibTexte('bib_v4_range_qty_ph', 0)); ?>"
|
||
<?php echo $blnRangeEditLocked ? 'readonly' : ''; ?>
|
||
<?php echo fxBibAideTippyAttr('bib_v4_col_qty'); ?>>
|
||
|
||
<?php echo fxBibRenderRangeOrCell(); ?>
|
||
|
||
<input type="number"
|
||
class="form-control form-control-sm bib-end"
|
||
min="1"
|
||
value="<?php echo ($tabSpec['end'] > 0) ? (int)$tabSpec['end'] : ''; ?>"
|
||
placeholder="<?php echo fxBibEsc(fxBibTexte('bib_v4_range_end_ph', 0)); ?>"
|
||
<?php echo $blnRangeEditLocked ? 'readonly' : ''; ?>
|
||
<?php echo fxBibAideTippyAttr('bib_v4_col_end'); ?>>
|
||
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button"
|
||
class="btn btn-sm btn-primary btn-save-range"
|
||
data-id="<?php echo $range['epr_bib_id']; ?>"
|
||
data-epr-id="<?php echo (int)$epr_id; ?>"
|
||
<?php echo $blnRangeEditLocked ? 'disabled' : ''; ?>>
|
||
<?php fxBibTexte('bib_v4_btn_ok', 1); ?>
|
||
</button>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_btn_ok'); ?>
|
||
<?php if ((int)$range['epr_bib_id'] > 0) { ?>
|
||
<button type="button"
|
||
class="btn btn-sm btn-danger btn-delete-range"
|
||
data-id="<?php echo $range['epr_bib_id']; ?>"
|
||
<?php echo $blnRangeEditLocked ? 'disabled' : ''; ?>>
|
||
<i class="fa fa-trash"></i>
|
||
</button>
|
||
<?php } else { ?>
|
||
<div></div>
|
||
<?php } ?>
|
||
<div class="epr-col-stats">
|
||
<div class="bib-last"><?php echo (int)$last; ?></div>
|
||
<div class="bib-used"><?php echo $range['nb_utilises']; ?></div>
|
||
<div class="bib-dispo" data-dispo="<?php echo $mem_dispo; ?>"><?php echo $mem_dispo; ?></div>
|
||
</div>
|
||
|
||
<div class="epr-col-batch">
|
||
<?php echo fxBibRenderRangeAutoBadge($range, $mode); ?>
|
||
<div class="batch-checkbox" style="text-align:center;">
|
||
|
||
<?php
|
||
|
||
$showCheckbox = false;
|
||
|
||
if (!$blnRangeLocked && (
|
||
$mode === 'assign'
|
||
&& $mem_dispo > 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;
|
||
}
|
||
|
||
?>
|
||
|
||
<?php if ($showCheckbox) { ?>
|
||
<input type="checkbox"
|
||
class="batch-select-range"
|
||
data-range-id="<?php echo (int)$range['epr_bib_id']; ?>"
|
||
<?php /* MSIN-4379 — Étape 2 : pré-cocher les séquences déjà en epr_bib_auto = 1. */ ?>
|
||
<?php if ($mode === 'auto' && (int)($range['epr_bib_auto'] ?? 0) === 1) { ?>checked<?php } ?>>
|
||
<?php } ?>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="bib-error text-danger small mb-2" style="<?php echo ((int)($range['nb_utilises'] ?? 0) > 0 && (!empty($range['liste_trous']) || !empty($range['liste_doublons']))) ? 'display:block;' : 'display:none;'; ?>">
|
||
<?php if ((int)($range['nb_utilises'] ?? 0) > 0 && !empty($range['liste_trous'])) { ?>
|
||
<div><?php fxBibTexteTrad('bib_v4_err_gaps', 1); ?> <?php echo fxBibEsc($range['liste_trous']); ?></div>
|
||
<?php } ?>
|
||
|
||
<?php if ((int)($range['nb_utilises'] ?? 0) > 0 && !empty($range['liste_doublons'])) { ?>
|
||
<div><?php fxBibTexteTrad('bib_v4_err_dupes', 1); ?> <?php echo fxBibEsc($range['liste_doublons']); ?></div>
|
||
<?php } ?>
|
||
</div>
|
||
|
||
<?php } ?>
|
||
|
||
<div class="bib-error-global text-danger small mb-2" style="display:none;"></div>
|
||
|
||
<?php if ($blnProductionLocked) { ?>
|
||
<div class="bib-production-range-lock-message text-danger small mb-2">
|
||
<i class="fa fa-lock mr-1" aria-hidden="true"></i>
|
||
<?php fxBibTexteTrad('bib_v5_production_locked_error', 1); ?>
|
||
</div>
|
||
<?php } else { ?>
|
||
<div class="epr-add-range-row">
|
||
<?php echo renderBibAddRangeButton($epr_id); ?>
|
||
</div>
|
||
<?php } ?>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
function renderBibView(
|
||
$epr_id,
|
||
$range_id = 0,
|
||
$strLangue = 'fr', // ✔️ on garde
|
||
$mode = 'db',
|
||
$data = [],
|
||
$title = '',
|
||
$info_text = '',
|
||
$status = 'default' // ← AJOUT
|
||
) {
|
||
global $objDatabase;
|
||
|
||
// =====================
|
||
// 1. GET RANGE
|
||
// =====================
|
||
$hasRange = intval($range_id) > 0;
|
||
|
||
if ($hasRange) {
|
||
|
||
$sqlRange = "
|
||
SELECT *
|
||
FROM inscriptions_epreuves_bib
|
||
WHERE epr_bib_id = " . intval($range_id);
|
||
|
||
$range = $objDatabase->fxGetRow($sqlRange);
|
||
|
||
if (!$range) {
|
||
return '<div class="epr-row-view">' . fxBibTexteTrad('bib_v4_view_range_not_found', 0) . '</div>';
|
||
}
|
||
|
||
$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 '<div class="epr-row-view">' . fxBibTexteTrad('bib_v4_view_epreuve_not_found', 0) . '</div>';
|
||
}
|
||
|
||
// =====================
|
||
// 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();
|
||
?>
|
||
|
||
<div class="epr-row-view" style="width:100%; background:#f8f9fa; padding:15px;">
|
||
|
||
<div class="bib-view <?php echo ((int)$tabEpreuve['epr_equipe'] === 1 ? 'team-mode' : ''); ?>">
|
||
<div class="bib-view-range">
|
||
|
||
<?php
|
||
// =====================
|
||
// TITRE DYNAMIQUE
|
||
// =====================
|
||
if ($title != '') {
|
||
|
||
echo $title;
|
||
|
||
} else {
|
||
|
||
if ($hasRange) {
|
||
echo fxBibMsgTrad('bib_v4_view_title_range', $start, $end);
|
||
} else {
|
||
fxBibTexteTrad('bib_v4_view_title_all', 1);
|
||
}
|
||
}
|
||
?>
|
||
|
||
</div>
|
||
|
||
<?php if ($info_text != '') { ?>
|
||
<div class="bib-view-info info-<?php echo $status; ?>">
|
||
<?php echo $info_text; ?>
|
||
</div>
|
||
<?php } ?>
|
||
<!-- HEADER — MSIN-4447 : X de fermeture en coin (même handler que le pied) -->
|
||
<div class="bib-view-header">
|
||
|
||
<div><?php fxBibTexteTrad('bib_v4_view_col_epreuve', 1); ?></div>
|
||
|
||
<div><?php fxBibTexteTrad('bib_v4_view_col_participant', 1); ?></div>
|
||
|
||
<?php if ((int)$tabEpreuve['epr_equipe'] === 1) { ?>
|
||
<div><?php fxBibTexteTrad('bib_v4_view_col_team_no', 1); ?></div>
|
||
<div><?php fxBibTexteTrad('bib_v4_view_col_team', 1); ?></div>
|
||
<?php } ?>
|
||
|
||
<div><?php fxBibTexteTrad('bib_v4_view_col_bib', 1); ?></div>
|
||
|
||
<button type="button"
|
||
class="btn-close-view bib-view-header__close epr-block-toggle"
|
||
aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v4_view_close', 0)); ?>"
|
||
title="<?php echo fxBibEsc(fxBibTexte('bib_v4_view_close', 0)); ?>">
|
||
<i class="fa fa-times" aria-hidden="true"></i>
|
||
</button>
|
||
|
||
</div>
|
||
|
||
<?php if (!empty($tabParticipants)) { ?>
|
||
|
||
<?php foreach ($tabParticipants as $p) {
|
||
|
||
if ($p['rol_id'] == 3 || $p['rol_id'] == 4) {
|
||
continue;
|
||
}
|
||
|
||
$blnCancelled = (int)($p['is_cancelled'] ?? 0) === 1 || (int)($p['pec_is_cancelled'] ?? 0) === 1;
|
||
$strNoBib = trim((string)($p['no_bib'] ?? ''));
|
||
?>
|
||
|
||
<div class="bib-view-row<?php echo $blnCancelled ? ' bib-view-row--cancelled' : ''; ?>">
|
||
|
||
<!-- Épreuve -->
|
||
<div class="bib-view-race">
|
||
<?php
|
||
if ($tabEpreuve['epr_nom_' . $strLangue] != '')
|
||
echo $tabEpreuve['epr_nom_' . $strLangue] . "<br>";
|
||
|
||
if ($tabEpreuve['epr_type_' . $strLangue] != '')
|
||
echo $tabEpreuve['epr_type_' . $strLangue];
|
||
|
||
echo " (" . $tabEpreuve['epr_id'] . ")";
|
||
?>
|
||
</div>
|
||
|
||
<!-- Participant -->
|
||
<div class="bib-view-name">
|
||
<?php echo fxBibEsc($p['par_prenom'] . ' ' . $p['par_nom']); ?>
|
||
<?php if ($blnCancelled) { ?>
|
||
<span class="bib-view-cancelled-label"><?php echo fxBibEsc(fxBibViewCancelledLabel($strLangue)); ?></span>
|
||
<?php } ?>
|
||
</div>
|
||
<?php if ((int)$tabEpreuve['epr_equipe'] === 1) { ?>
|
||
|
||
<div class="bib-view-team-number">
|
||
<?php
|
||
echo $p['no_equipe'];
|
||
?>
|
||
</div>
|
||
|
||
<div class="bib-view-team">
|
||
|
||
<?php
|
||
echo $p['pec_nom_equipe'];
|
||
|
||
if ((int)$p['rol_id'] === 1) {
|
||
echo ' ' . fxBibTexteTrad('bib_v4_view_captain', 0);
|
||
}
|
||
?>
|
||
|
||
</div>
|
||
|
||
<?php } ?>
|
||
<!-- Numéro -->
|
||
<div class="bib-view-number">
|
||
<strong><?php echo $strNoBib !== '' && $strNoBib !== '0' ? fxBibEsc($strNoBib) : '—'; ?></strong>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<?php } ?>
|
||
|
||
<?php } else { ?>
|
||
|
||
<div class="bib-view-empty">
|
||
<?php fxBibTexteTrad('bib_v4_view_empty', 1); ?>
|
||
</div>
|
||
|
||
<?php } ?>
|
||
|
||
<!-- FOOTER -->
|
||
<div class="bib-view-footer">
|
||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||
<button type="button" class="btn btn-sm btn-secondary btn-close-view">
|
||
<?php fxBibTexte('bib_v4_view_close', 1); ?>
|
||
</button>
|
||
<?php echo fxBibBtnAideSegmentClose('bib_v4_view_close'); ?>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
function fxGetParticipantsForBatchAssign($epr_id, $sort1, $sort2 = '') {
|
||
global $objDatabase, $strLangue;
|
||
|
||
$epr_id = intval($epr_id);
|
||
|
||
// Legacy : fxGetParticipantsForBatchAssign($epr_id, $ba_id)
|
||
if (func_num_args() === 2 && is_numeric($sort1) && strpos(trim((string)$sort1), ':') === false) {
|
||
$sort1 = fxBibSortKeyFromBaId((int)$sort1);
|
||
$sort2 = '';
|
||
}
|
||
|
||
$strSort1 = fxBibNormalizeSortKey($sort1);
|
||
$strSort2 = fxBibNormalizeSortKey($sort2);
|
||
|
||
if ($epr_id <= 0 || $strSort1 === '') {
|
||
return [];
|
||
}
|
||
|
||
if ($strSort1 === $strSort2) {
|
||
$strSort2 = '';
|
||
}
|
||
|
||
$orderBy = fxBibBuildBatchOrderBy($epr_id, $strSort1, $strSort2, $strLangue ?? 'fr');
|
||
|
||
// =====================
|
||
// 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
|
||
";
|
||
|
||
$tabParticipants = $objDatabase->fxGetResults($sql);
|
||
if (!is_array($tabParticipants) || empty($tabParticipants)) {
|
||
return is_array($tabParticipants) ? $tabParticipants : [];
|
||
}
|
||
|
||
// MSIN-4456 — Filet : si tri principal = nom d'équipe, forcer le regroupement en PHP
|
||
// (dossards individuels comme 1 équipe = 1 dossard).
|
||
if (fxBibSortKeyIsTeamCriterion($strSort1)) {
|
||
$tabParticipants = fxBibSortParticipantsByTeamName($tabParticipants);
|
||
}
|
||
|
||
return $tabParticipants;
|
||
}
|
||
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;
|
||
|
||
// MSIN-4328 — par_maj pour que ChronoTrack détecte le changement de dossard
|
||
$sqlUpdate = "
|
||
UPDATE resultats_participants
|
||
SET no_bib = " . intval($foundBib) . ",
|
||
par_date_bib = IFNULL(par_date_bib, NOW()),
|
||
par_maj = '" . fxGetDateTime() . "'
|
||
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) {
|
||
global $objDatabase;
|
||
|
||
$assignments = [];
|
||
$teamMap = [];
|
||
$updatedTeams = [];
|
||
$teamBibMap = [];
|
||
// MSIN-4477 — Poursuivre (dossards individuels) : reprendre après le max déjà attribué
|
||
// pour éviter les doublons no_equipe avec les équipes déjà numérotées.
|
||
$nextTeamNumber = 1;
|
||
if ($teamMode !== 3) {
|
||
$sqlMaxTeam = "
|
||
SELECT MAX(CAST(no_equipe AS UNSIGNED))
|
||
FROM resultats_epreuves_commandees
|
||
WHERE epr_id = " . intval($epr_id) . "
|
||
";
|
||
$nextTeamNumber = (int)$objDatabase->fxGetVar($sqlMaxTeam) + 1;
|
||
if ($nextTeamNumber < 1) {
|
||
$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])) {
|
||
// MSIN-4477 — Réutiliser le no_equipe déjà en BD (équipe partiellement assignée).
|
||
$existingTeamNo = (int)($p['no_equipe'] ?? 0);
|
||
if ($existingTeamNo > 0) {
|
||
$teamMap[$teamKey] = $existingTeamNo;
|
||
} else {
|
||
$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
|
||
];
|
||
}
|
||
/**
|
||
* MSIN-4453 — Efface no_equipe après réinitialisation des dossards (aligné sur le reset legacy).
|
||
* Sans $tabParticipants : toute l'épreuve. Avec liste (reset par séquences) : uniquement les équipes
|
||
* dont plus aucun membre actif n'a de dossard.
|
||
*/
|
||
function fxClearTeamNumbersAfterBibReset($epr_id, $tabParticipants = null) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
|
||
if ($epr_id <= 0) {
|
||
return;
|
||
}
|
||
|
||
if ($tabParticipants === null) {
|
||
$sql = "
|
||
UPDATE resultats_epreuves_commandees
|
||
SET no_equipe = NULL
|
||
WHERE epr_id = $epr_id
|
||
";
|
||
$objDatabase->fxQuery($sql);
|
||
return;
|
||
}
|
||
|
||
$teamKeys = [];
|
||
|
||
foreach ($tabParticipants as $p) {
|
||
$teamKey = fxGetBatchTeamKey($p);
|
||
|
||
if ($teamKey > 0) {
|
||
$teamKeys[$teamKey] = true;
|
||
}
|
||
}
|
||
|
||
if (empty($teamKeys)) {
|
||
return;
|
||
}
|
||
|
||
$ids = implode(',', array_map('intval', array_keys($teamKeys)));
|
||
$sqlBibNum = fxBibSqlNoBibUnsigned('p.no_bib');
|
||
|
||
$sql = "
|
||
UPDATE resultats_epreuves_commandees c
|
||
SET c.no_equipe = NULL
|
||
WHERE c.epr_id = $epr_id
|
||
AND c.pec_id_original IN ($ids)
|
||
AND NOT EXISTS (
|
||
SELECT 1
|
||
FROM resultats_participants p
|
||
WHERE p.pec_id = c.pec_id_original
|
||
AND p.epr_id = c.epr_id
|
||
AND p.is_cancelled = 0
|
||
AND p.no_bib IS NOT NULL
|
||
AND $sqlBibNum > 0
|
||
)
|
||
";
|
||
|
||
$objDatabase->fxQuery($sql);
|
||
}
|
||
|
||
/** MSIN-4436 — Tous les participants avec dossard sur l'épreuve (y compris hors séquences). */
|
||
function fxGetParticipantsForEpreuveResetAll($epr_id) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
|
||
if ($epr_id <= 0) {
|
||
return [];
|
||
}
|
||
|
||
$sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib');
|
||
|
||
$sql = "
|
||
SELECT p.*
|
||
FROM resultats_participants p
|
||
WHERE p.epr_id = $epr_id
|
||
AND p.is_cancelled = 0
|
||
AND p.no_bib IS NOT NULL
|
||
AND p.no_bib > 0
|
||
ORDER BY $sqlBibNumP
|
||
";
|
||
|
||
return $objDatabase->fxGetResults($sql);
|
||
}
|
||
|
||
function fxGetParticipantsForBatchReset($epr_id, $ranges) {
|
||
|
||
global $objDatabase;
|
||
|
||
$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;
|
||
}
|
||
|
||
// =============================================================================
|
||
// MSIN-4433 — Impression PDF distribution des dossards
|
||
// =============================================================================
|
||
|
||
/** MSIN-4433 / MSIN-4471 — Limite de colonnes questions (feuille bénévole lettre). */
|
||
function fxBibDistPrintMaxQuestions() {
|
||
return 3;
|
||
}
|
||
|
||
/** MSIN-4433 — Nom affiché du compte connecté (promoteur ou superadmin). */
|
||
function fxBibGetCurrentPromoteurDisplayName() {
|
||
if (!empty($_SESSION['usa_id']) && !empty($_SESSION['usa_info']) && is_array($_SESSION['usa_info'])) {
|
||
$str = trim((string)($_SESSION['usa_info']['com_prenom'] ?? '') . ' ' . (string)($_SESSION['usa_info']['com_nom'] ?? ''));
|
||
if ($str !== '') {
|
||
return $str;
|
||
}
|
||
}
|
||
if (!empty($_SESSION['com_info']) && is_array($_SESSION['com_info'])) {
|
||
$str = trim((string)($_SESSION['com_info']['com_prenom'] ?? '') . ' ' . (string)($_SESSION['com_info']['com_nom'] ?? ''));
|
||
if ($str !== '') {
|
||
return $str;
|
||
}
|
||
}
|
||
return trim((string)($_SESSION['com_prenom'] ?? '') . ' ' . (string)($_SESSION['com_nom'] ?? ''));
|
||
}
|
||
|
||
/** MSIN-4433 — Accès génération PDF (session promoteur + CSRF, pas de granularite v2 pour l'instant). */
|
||
function fxBibRequireDistPrintAccess() {
|
||
if (!fxBibRequirePromoteurSession()) {
|
||
http_response_code(403);
|
||
header('Content-Type: text/plain; charset=utf-8');
|
||
echo fxBibMsg('bib_v4_ajax_session_invalid');
|
||
exit;
|
||
}
|
||
|
||
$strToken = $_POST['csrf_token'] ?? $_REQUEST['csrf_token'] ?? '';
|
||
if (!fxBibValidateCsrf($strToken)) {
|
||
http_response_code(403);
|
||
header('Content-Type: text/plain; charset=utf-8');
|
||
echo fxBibMsg('bib_v4_ajax_unauthorized');
|
||
exit;
|
||
}
|
||
}
|
||
|
||
/** MSIN-4433 — Parse liste d'IDs questions depuis chaîne CSV. */
|
||
function fxBibParseDistPrintQueIds($strCsv) {
|
||
if ($strCsv === null || $strCsv === '') {
|
||
return [];
|
||
}
|
||
$out = [];
|
||
foreach (explode(',', (string)$strCsv) as $part) {
|
||
$intId = (int)trim($part);
|
||
if ($intId > 0 && !in_array($intId, $out, true)) {
|
||
$out[] = $intId;
|
||
}
|
||
}
|
||
return $out;
|
||
}
|
||
|
||
/** MSIN-4433 — Sérialise les IDs questions pour stockage. */
|
||
function fxBibDistPrintQueIdsToCsv(array $tabQueIds) {
|
||
$out = [];
|
||
foreach ($tabQueIds as $mixId) {
|
||
$intId = (int)$mixId;
|
||
if ($intId > 0 && !in_array($intId, $out, true)) {
|
||
$out[] = $intId;
|
||
}
|
||
}
|
||
return implode(',', $out);
|
||
}
|
||
|
||
/** MSIN-4433 — Libellé court sexe pour le PDF. */
|
||
function fxBibDistPrintSexeLabel($strSexe, $strLangue = 'fr') {
|
||
$strSexe = strtolower(trim((string)$strSexe));
|
||
if ($strLangue === 'en') {
|
||
$tab = ['f' => 'F', 'h' => 'M', 'n' => 'X', 'a' => 'O'];
|
||
} else {
|
||
$tab = ['f' => 'F', 'h' => 'H', 'n' => 'X', 'a' => 'A'];
|
||
}
|
||
return $tab[$strSexe] ?? strtoupper($strSexe);
|
||
}
|
||
|
||
/** MSIN-4433 — Date/heure affichée (pied de page, panneau). */
|
||
function fxBibFormatDistPrintDateTime($strWhen = '', $strLangue = 'fr') {
|
||
$ts = ($strWhen !== '') ? strtotime($strWhen) : time();
|
||
if ($ts === false) {
|
||
$ts = time();
|
||
}
|
||
if ($strLangue === 'en') {
|
||
return date('F j, Y, g:i a', $ts);
|
||
}
|
||
$tabMonths = [
|
||
1 => 'janvier', 2 => 'février', 3 => 'mars', 4 => 'avril',
|
||
5 => 'mai', 6 => 'juin', 7 => 'juillet', 8 => 'août',
|
||
9 => 'septembre', 10 => 'octobre', 11 => 'novembre', 12 => 'décembre',
|
||
];
|
||
$intDay = (int)date('j', $ts);
|
||
$intMonth = (int)date('n', $ts);
|
||
$intYear = (int)date('Y', $ts);
|
||
$strTime = date('H:i', $ts);
|
||
return $intDay . ' ' . ($tabMonths[$intMonth] ?? '') . ' ' . $intYear . ', ' . $strTime;
|
||
}
|
||
|
||
/** MSIN-4433 — Métadonnées dernière impression (événement). */
|
||
function fxBibGetDistPrintMeta($int_eve_id) {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($int_eve_id <= 0) {
|
||
return ['at' => '', 'by' => '', 'com_id' => 0];
|
||
}
|
||
|
||
$row = $objDatabase->fxGetRow("
|
||
SELECT eve_bib_dist_print_at, eve_bib_dist_print_by, eve_bib_dist_print_com_id
|
||
FROM inscriptions_evenements
|
||
WHERE eve_id = $int_eve_id
|
||
LIMIT 1
|
||
");
|
||
|
||
if (!is_array($row)) {
|
||
return ['at' => '', 'by' => '', 'com_id' => 0];
|
||
}
|
||
|
||
return [
|
||
'at' => trim((string)($row['eve_bib_dist_print_at'] ?? '')),
|
||
'by' => trim((string)($row['eve_bib_dist_print_by'] ?? '')),
|
||
'com_id' => (int)($row['eve_bib_dist_print_com_id'] ?? 0),
|
||
];
|
||
}
|
||
|
||
/** MSIN-4433 — Persiste date / auteur de l'impression. */
|
||
function fxBibSaveDistPrintMeta($int_eve_id, $int_com_id, $str_by) {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$int_com_id = (int)$int_com_id;
|
||
$str_by = trim((string)$str_by);
|
||
if ($int_eve_id <= 0) {
|
||
return;
|
||
}
|
||
|
||
$sql = "
|
||
UPDATE inscriptions_evenements
|
||
SET eve_bib_dist_print_at = '" . $objDatabase->fxEscape(fxGetDateTime()) . "',
|
||
eve_bib_dist_print_by = '" . $objDatabase->fxEscape($str_by) . "',
|
||
eve_bib_dist_print_com_id = $int_com_id
|
||
WHERE eve_id = $int_eve_id
|
||
LIMIT 1
|
||
";
|
||
$objDatabase->fxQuery($sql);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4433 — Données panneau : épreuves, questions éligibles, sélection mémorisée.
|
||
* @return array{meta: array, epreuves: array<int, array<string, mixed>>}
|
||
*/
|
||
function fxBibCollectDistPrintPanelData($int_eve_id, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
$tabOut = ['meta' => fxBibGetDistPrintMeta($int_eve_id), 'epreuves' => []];
|
||
|
||
if ($int_eve_id <= 0) {
|
||
return $tabOut;
|
||
}
|
||
|
||
$sqlEpreuves = "
|
||
SELECT *
|
||
FROM inscriptions_epreuves
|
||
WHERE eve_id = $int_eve_id
|
||
AND epr_actif = 1
|
||
ORDER BY epr_tri, epr_id
|
||
";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
if (!is_array($tabEpreuves)) {
|
||
return $tabOut;
|
||
}
|
||
|
||
foreach ($tabEpreuves as $epr) {
|
||
$epr_id = (int)($epr['epr_id'] ?? 0);
|
||
if ($epr_id <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$tabQuestionOpts = fxBibGetQuestionSortOptions($epr_id, $int_eve_id, $strLangue);
|
||
$tabSelected = fxBibParseDistPrintQueIds($epr['ba_bib_dist_que_ids'] ?? '');
|
||
$tabValidIds = [];
|
||
foreach ($tabQuestionOpts as $opt) {
|
||
if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) {
|
||
$tabValidIds[] = (int)$m[1];
|
||
}
|
||
}
|
||
$tabSelected = array_values(array_intersect($tabSelected, $tabValidIds));
|
||
|
||
$tabOut['epreuves'][] = [
|
||
'epr_id' => $epr_id,
|
||
'epr_label' => fxBibAnomalyEprLabel($epr, $strLangue),
|
||
'questions' => $tabQuestionOpts,
|
||
'selected' => $tabSelected,
|
||
'avec_bib' => (int)(fxInfosBibEpreuve($epr_id)['avec_bib'] ?? 0),
|
||
];
|
||
}
|
||
|
||
return $tabOut;
|
||
}
|
||
|
||
/** MSIN-4433 — Parse sélections POST dist_print[epr_id][] = que_id. */
|
||
function fxBibParseDistPrintSelectionsFromPost(array $post) {
|
||
$tabRaw = $post['dist_print'] ?? [];
|
||
if (!is_array($tabRaw)) {
|
||
return [];
|
||
}
|
||
|
||
$out = [];
|
||
foreach ($tabRaw as $mixEprId => $mixQueIds) {
|
||
$epr_id = (int)$mixEprId;
|
||
if ($epr_id <= 0) {
|
||
continue;
|
||
}
|
||
if (!is_array($mixQueIds)) {
|
||
$mixQueIds = [$mixQueIds];
|
||
}
|
||
$tabIds = [];
|
||
foreach ($mixQueIds as $mixQueId) {
|
||
$intQueId = (int)$mixQueId;
|
||
if ($intQueId > 0 && !in_array($intQueId, $tabIds, true)) {
|
||
$tabIds[] = $intQueId;
|
||
}
|
||
}
|
||
$out[$epr_id] = $tabIds;
|
||
}
|
||
|
||
return $out;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4433 — Sauvegarde les questions cochées par épreuve (à la génération PDF).
|
||
* @return array{success: bool, message?: string}
|
||
*/
|
||
function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($int_eve_id <= 0) {
|
||
return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')];
|
||
}
|
||
|
||
$intMax = fxBibDistPrintMaxQuestions();
|
||
$tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue);
|
||
|
||
foreach ($tabPanel['epreuves'] as $tabEpr) {
|
||
$epr_id = (int)($tabEpr['epr_id'] ?? 0);
|
||
if ($epr_id <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$tabValidIds = [];
|
||
foreach ($tabEpr['questions'] as $opt) {
|
||
if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) {
|
||
$tabValidIds[] = (int)$m[1];
|
||
}
|
||
}
|
||
|
||
$tabChosen = $tabSelections[$epr_id] ?? [];
|
||
if (!is_array($tabChosen)) {
|
||
$tabChosen = [];
|
||
}
|
||
|
||
$tabFiltered = [];
|
||
foreach ($tabChosen as $intQueId) {
|
||
$intQueId = (int)$intQueId;
|
||
if ($intQueId > 0 && in_array($intQueId, $tabValidIds, true)
|
||
&& !in_array($intQueId, $tabFiltered, true)) {
|
||
$tabFiltered[] = $intQueId;
|
||
}
|
||
}
|
||
|
||
if (count($tabFiltered) > $intMax) {
|
||
// MSIN-4471 — Max abaissé à 3 : garder les N premières plutôt que bloquer.
|
||
$tabFiltered = array_slice($tabFiltered, 0, $intMax);
|
||
}
|
||
|
||
$strCsv = fxBibDistPrintQueIdsToCsv($tabFiltered);
|
||
$sql = "
|
||
UPDATE inscriptions_epreuves
|
||
SET ba_bib_dist_que_ids = '" . $objDatabase->fxEscape($strCsv) . "'
|
||
WHERE epr_id = $epr_id
|
||
AND eve_id = $int_eve_id
|
||
LIMIT 1
|
||
";
|
||
$objDatabase->fxQuery($sql);
|
||
}
|
||
|
||
return ['success' => true];
|
||
}
|
||
|
||
/**
|
||
* MSIN-4433 / MSIN-4471 — Participants avec dossard (une ligne par no_bib).
|
||
* Tri fixe nom + prénom : les bénévoles cherchent par nom à la table.
|
||
* ($sort1 / $sort2 conservés pour compat signature ; ignorés.)
|
||
* @return array<int, array<string, mixed>>
|
||
*/
|
||
function fxBibGetParticipantsForDistPrint($epr_id, $sort1, $sort2 = '', $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
if ($epr_id <= 0) {
|
||
return [];
|
||
}
|
||
|
||
$sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib');
|
||
// MSIN-4471 — Toujours alphabétique nom / prénom (pas le tri batch d'assignation).
|
||
$orderBy = 'TRIM(p.par_nom), TRIM(p.par_prenom), p.par_id ASC';
|
||
|
||
$sql = "
|
||
SELECT
|
||
p.par_id,
|
||
p.par_id_original,
|
||
p.pec_id,
|
||
p.no_bib,
|
||
p.par_nom,
|
||
p.par_prenom,
|
||
p.par_sexe
|
||
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.is_cancelled = 0
|
||
AND $sqlBibNumP > 0
|
||
AND p.rol_id NOT IN (3, 4)
|
||
ORDER BY $orderBy
|
||
";
|
||
|
||
$rows = $objDatabase->fxGetResults($sql);
|
||
if (!is_array($rows)) {
|
||
return [];
|
||
}
|
||
|
||
$tabSeen = [];
|
||
$tabOut = [];
|
||
foreach ($rows as $row) {
|
||
$strBibKey = (string)(int)($row['no_bib'] ?? 0);
|
||
if ($strBibKey === '0' || isset($tabSeen[$strBibKey])) {
|
||
continue;
|
||
}
|
||
$tabSeen[$strBibKey] = true;
|
||
$tabOut[] = $row;
|
||
}
|
||
|
||
return $tabOut;
|
||
}
|
||
|
||
/** MSIN-4433 — Clé de correspondance participant ↔ réponse question. */
|
||
function fxBibDistPrintAnswerKey(array $row) {
|
||
$intPecId = (int)($row['pec_id'] ?? 0);
|
||
$intParLookup = (int)($row['par_id_original'] ?? 0);
|
||
if ($intParLookup <= 0) {
|
||
$intParLookup = (int)($row['par_id'] ?? 0);
|
||
}
|
||
return $intParLookup . ':' . $intPecId;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4433 — Réponses questions pour une liste de participants.
|
||
* resultats_questions.par_id = resultats_participants.par_id_original (legacy MS1).
|
||
* @return array<string, array<int, string>> clé "par_lookup:pec_id" => [que_id => réponse]
|
||
*/
|
||
function fxBibGetDistPrintQuestionAnswers($epr_id, array $tabQueIds, array $tabParticipants, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
$tabQueIds = array_values(array_filter(array_map('intval', $tabQueIds)));
|
||
if ($epr_id <= 0 || empty($tabQueIds) || empty($tabParticipants)) {
|
||
return [];
|
||
}
|
||
|
||
$tabParIds = [];
|
||
foreach ($tabParticipants as $row) {
|
||
$intParId = (int)($row['par_id'] ?? 0);
|
||
if ($intParId > 0) {
|
||
$tabParIds[] = $intParId;
|
||
}
|
||
}
|
||
$tabParIds = array_values(array_unique($tabParIds));
|
||
if (empty($tabParIds)) {
|
||
return [];
|
||
}
|
||
|
||
$strCol = ($strLangue === 'en') ? 'que_choix_en' : 'que_choix_fr';
|
||
$strQueIds = implode(',', $tabQueIds);
|
||
$strParIds = implode(',', $tabParIds);
|
||
|
||
$sql = "
|
||
SELECT
|
||
p.par_id,
|
||
p.par_id_original,
|
||
p.pec_id,
|
||
rq.que_id,
|
||
TRIM(COALESCE(NULLIF(rq.$strCol, ''), NULLIF(rq.pqu_note, ''), NULLIF(rq.que_choix_fr, ''))) AS ans
|
||
FROM resultats_participants p
|
||
INNER JOIN resultats_questions rq
|
||
ON rq.pec_id = p.pec_id
|
||
AND rq.par_id = IF(p.par_id_original > 0, p.par_id_original, p.par_id)
|
||
WHERE p.epr_id = $epr_id
|
||
AND p.par_id IN ($strParIds)
|
||
AND rq.que_id IN ($strQueIds)
|
||
";
|
||
$rows = $objDatabase->fxGetResults($sql);
|
||
if (!is_array($rows)) {
|
||
return [];
|
||
}
|
||
|
||
$out = [];
|
||
foreach ($rows as $row) {
|
||
$strKey = fxBibDistPrintAnswerKey($row);
|
||
$intQueId = (int)($row['que_id'] ?? 0);
|
||
$out[$strKey][$intQueId] = trim((string)($row['ans'] ?? ''));
|
||
}
|
||
|
||
return $out;
|
||
}
|
||
|
||
/** MSIN-4433 — Tronque texte pour cellule PDF. */
|
||
function fxBibDistPrintTruncate($str, $intMax = 28) {
|
||
$str = trim((string)$str);
|
||
if ($str === '') {
|
||
return '';
|
||
}
|
||
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
|
||
if (mb_strlen($str) <= $intMax) {
|
||
return $str;
|
||
}
|
||
return mb_substr($str, 0, max(1, $intMax - 1)) . '…';
|
||
}
|
||
if (strlen($str) <= $intMax) {
|
||
return $str;
|
||
}
|
||
return substr($str, 0, max(1, $intMax - 1)) . '…';
|
||
}
|
||
|
||
/** MSIN-4470 — Convertit l'UTF-8 vers l'encodage Windows-1252 attendu par les polices FPDF. */
|
||
function fxBibDistPrintPdfText($str) {
|
||
$str = (string)$str;
|
||
if (function_exists('iconv')) {
|
||
$strConverted = @iconv('UTF-8', 'Windows-1252//TRANSLIT', $str);
|
||
if ($strConverted !== false) {
|
||
return $strConverted;
|
||
}
|
||
}
|
||
return utf8_decode($str);
|
||
}
|
||
|
||
/** MSIN-4471 — Clés doc_page des 3 pages d'intro (ordre d'impression). */
|
||
function fxBibDistPrintIntroPageClefs() {
|
||
return array(
|
||
'bib_dist_print_reco',
|
||
'bib_dist_print_table',
|
||
'bib_dist_print_qr',
|
||
);
|
||
}
|
||
|
||
/** MSIN-4471 — Chemin absolu du logo MS1 (pied / bandeau PDF). */
|
||
function fxBibDistPrintMs1LogoPath() {
|
||
$strDocRoot = $_SERVER['DOCUMENT_ROOT'] ?? dirname(__DIR__);
|
||
$strPath = rtrim($strDocRoot, '/\\') . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'logoms1inscription.png';
|
||
return is_file($strPath) ? $strPath : '';
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — Texte brut d'un nœud DOM (espaces normalisés).
|
||
*/
|
||
function fxBibDistPrintDomPlainText($node) {
|
||
if (!$node) {
|
||
return '';
|
||
}
|
||
$str = $node->textContent ?? '';
|
||
$str = preg_replace('/\s+/u', ' ', $str);
|
||
return trim((string)$str);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — Écrit un fragment inline (texte + strong/em) en mode Write.
|
||
*/
|
||
function fxBibDistPrintWriteInline($pdf, $node, $fltLineH = 5, $fltFontSize = 10) {
|
||
if (!$node) {
|
||
return;
|
||
}
|
||
foreach ($node->childNodes as $child) {
|
||
if ($child->nodeType === XML_TEXT_NODE) {
|
||
$strText = preg_replace('/\s+/u', ' ', $child->nodeValue);
|
||
if ($strText !== null && $strText !== '') {
|
||
$pdf->SetFont('Arial', '', $fltFontSize);
|
||
$pdf->Write($fltLineH, fxBibDistPrintPdfText($strText));
|
||
}
|
||
continue;
|
||
}
|
||
if ($child->nodeType !== XML_ELEMENT_NODE) {
|
||
continue;
|
||
}
|
||
$strTag = strtolower($child->nodeName);
|
||
if ($strTag === 'br') {
|
||
$pdf->Ln($fltLineH);
|
||
continue;
|
||
}
|
||
if (in_array($strTag, array('strong', 'b'), true)) {
|
||
$strText = fxBibDistPrintDomPlainText($child);
|
||
if ($strText !== '') {
|
||
$pdf->SetFont('Arial', 'B', $fltFontSize);
|
||
$pdf->Write($fltLineH, fxBibDistPrintPdfText($strText));
|
||
$pdf->SetFont('Arial', '', $fltFontSize);
|
||
}
|
||
continue;
|
||
}
|
||
if (in_array($strTag, array('em', 'i'), true)) {
|
||
$strText = fxBibDistPrintDomPlainText($child);
|
||
if ($strText !== '') {
|
||
$pdf->SetFont('Arial', 'I', $fltFontSize);
|
||
$pdf->Write($fltLineH, fxBibDistPrintPdfText($strText));
|
||
$pdf->SetFont('Arial', '', $fltFontSize);
|
||
}
|
||
continue;
|
||
}
|
||
fxBibDistPrintWriteInline($pdf, $child, $fltLineH, $fltFontSize);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — Résout un src img vers un fichier sous images/doc/ uniquement.
|
||
* Accepte /images/doc/x.png, images/doc/x.png (refuse tout autre chemin).
|
||
*/
|
||
function fxBibDistPrintResolveDocImagePath($strSrc) {
|
||
$strSrc = trim((string)$strSrc);
|
||
if ($strSrc === '') {
|
||
return '';
|
||
}
|
||
$strSrc = str_replace('\\', '/', $strSrc);
|
||
$strSrc = preg_replace('#^https?://[^/]+#i', '', $strSrc);
|
||
$strSrc = ltrim($strSrc, '/');
|
||
if (strpos($strSrc, 'images/doc/') !== 0) {
|
||
return '';
|
||
}
|
||
$strRel = substr($strSrc, strlen('images/doc/'));
|
||
if ($strRel === '' || strpos($strRel, '..') !== false) {
|
||
return '';
|
||
}
|
||
$strDocRoot = $_SERVER['DOCUMENT_ROOT'] ?? dirname(__DIR__);
|
||
$strPath = rtrim($strDocRoot, '/\\') . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'doc' . DIRECTORY_SEPARATOR
|
||
. str_replace('/', DIRECTORY_SEPARATOR, $strRel);
|
||
if (!is_file($strPath)) {
|
||
return '';
|
||
}
|
||
$strExt = strtolower(pathinfo($strPath, PATHINFO_EXTENSION));
|
||
if (!in_array($strExt, array('png', 'jpg', 'jpeg', 'gif'), true)) {
|
||
return '';
|
||
}
|
||
return $strPath;
|
||
}
|
||
|
||
/** MSIN-4471 — Insère une image doc (largeur max = page utile, ou $fltMaxWMm si fourni). */
|
||
function fxBibDistPrintWriteImage($pdf, $strPath, $fltMaxWMm = 0, $blnCenter = false) {
|
||
if ($strPath === '' || !is_file($strPath)) {
|
||
return;
|
||
}
|
||
$fltLeft = method_exists($pdf, 'GetLeftMargin') ? $pdf->GetLeftMargin() : 10;
|
||
$fltRight = method_exists($pdf, 'GetRightMargin') ? $pdf->GetRightMargin() : 10;
|
||
$fltBottom = method_exists($pdf, 'GetBreakMargin') ? $pdf->GetBreakMargin() : 14;
|
||
$fltPageMax = $pdf->GetPageWidth() - $fltLeft - $fltRight;
|
||
$fltMaxW = ($fltMaxWMm > 0) ? min($fltMaxWMm, $fltPageMax) : $fltPageMax;
|
||
$tabSize = @getimagesize($strPath);
|
||
if (!is_array($tabSize) || empty($tabSize[0]) || empty($tabSize[1])) {
|
||
return;
|
||
}
|
||
|
||
// FPDF se fie à l'extension : forcer le type réel (ex. JPEG nommé .png).
|
||
$strType = '';
|
||
$strMime = isset($tabSize['mime']) ? strtolower((string)$tabSize['mime']) : '';
|
||
if ($strMime === 'image/jpeg' || $strMime === 'image/jpg') {
|
||
$strType = 'JPG';
|
||
} elseif ($strMime === 'image/png') {
|
||
$strType = 'PNG';
|
||
} elseif ($strMime === 'image/gif') {
|
||
$strType = 'GIF';
|
||
} else {
|
||
return;
|
||
}
|
||
|
||
$fltW = $fltMaxW;
|
||
$fltNatW = ($tabSize[0] * 25.4) / 96;
|
||
if ($fltNatW > 0 && $fltNatW < $fltMaxW) {
|
||
$fltW = $fltNatW;
|
||
}
|
||
$fltH = $fltW * ($tabSize[1] / $tabSize[0]);
|
||
if ($pdf->GetY() + max(10, $fltH) > $pdf->GetPageHeight() - $fltBottom) {
|
||
$pdf->AddPage();
|
||
}
|
||
$fltX = $blnCenter ? (($pdf->GetPageWidth() - $fltW) / 2) : $pdf->GetX();
|
||
$pdf->Image($strPath, $fltX, $pdf->GetY(), $fltW, 0, $strType);
|
||
$pdf->Ln(max(8, $fltH + 3));
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — Rendu flyer des pages intro (bandeau déjà dans Header).
|
||
* Structure attendue : lead <p> puis blocs <h3>+<p> (cartes numérotées).
|
||
* Si pas de h3 : repli sur fxBibDistPrintWriteHtml.
|
||
*/
|
||
function fxBibDistPrintWriteIntroFlyer($pdf, $strHtml) {
|
||
$strHtml = trim((string)$strHtml);
|
||
if ($strHtml === '') {
|
||
return;
|
||
}
|
||
if (!class_exists('DOMDocument', false)) {
|
||
fxBibDistPrintWriteHtml($pdf, $strHtml);
|
||
return;
|
||
}
|
||
|
||
$dom = new DOMDocument();
|
||
$blnPrev = libxml_use_internal_errors(true);
|
||
$dom->loadHTML(
|
||
'<?xml encoding="UTF-8"><div id="ms1-bib-dist-root">' . $strHtml . '</div>',
|
||
LIBXML_HTML_NODEFDTD
|
||
);
|
||
libxml_clear_errors();
|
||
libxml_use_internal_errors($blnPrev);
|
||
|
||
$root = $dom->getElementById('ms1-bib-dist-root');
|
||
if (!$root) {
|
||
foreach ($dom->getElementsByTagName('div') as $el) {
|
||
if ($el->getAttribute('id') === 'ms1-bib-dist-root') {
|
||
$root = $el;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (!$root) {
|
||
fxBibDistPrintWriteHtml($pdf, $strHtml);
|
||
return;
|
||
}
|
||
|
||
// Déballer <article> si présent.
|
||
$article = null;
|
||
foreach ($root->childNodes as $child) {
|
||
if ($child->nodeType === XML_ELEMENT_NODE && strtolower($child->nodeName) === 'article') {
|
||
$article = $child;
|
||
break;
|
||
}
|
||
}
|
||
$scope = $article ?: $root;
|
||
|
||
$tabBlocks = array();
|
||
foreach ($scope->childNodes as $child) {
|
||
if ($child->nodeType !== XML_ELEMENT_NODE) {
|
||
continue;
|
||
}
|
||
$strTag = strtolower($child->nodeName);
|
||
if (in_array($strTag, array('p', 'h2', 'h3', 'h4', 'ul', 'ol', 'blockquote', 'img'), true)) {
|
||
$tabBlocks[] = $child;
|
||
}
|
||
}
|
||
|
||
$blnHasH3 = false;
|
||
foreach ($tabBlocks as $el) {
|
||
if (strtolower($el->nodeName) === 'h3') {
|
||
$blnHasH3 = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!$blnHasH3) {
|
||
fxBibDistPrintWriteHtml($pdf, $strHtml);
|
||
return;
|
||
}
|
||
|
||
$fltLeft = method_exists($pdf, 'GetLeftMargin') ? $pdf->GetLeftMargin() : 12;
|
||
$fltRight = method_exists($pdf, 'GetRightMargin') ? $pdf->GetRightMargin() : 12;
|
||
$fltBottom = method_exists($pdf, 'GetBreakMargin') ? $pdf->GetBreakMargin() : 18;
|
||
$fltPageW = $pdf->GetPageWidth();
|
||
$fltContentW = $fltPageW - $fltLeft - $fltRight;
|
||
$intTip = 0;
|
||
$blnLeadDone = false;
|
||
|
||
$i = 0;
|
||
$intN = count($tabBlocks);
|
||
while ($i < $intN) {
|
||
$el = $tabBlocks[$i];
|
||
$strTag = strtolower($el->nodeName);
|
||
|
||
// Premier <p> = encadré d'intro (lead).
|
||
if ($strTag === 'p' && !$blnLeadDone) {
|
||
$blnLeadDone = true;
|
||
$strLead = fxBibDistPrintDomPlainText($el);
|
||
$fltInnerW = $fltContentW - 10;
|
||
$pdf->SetFont('Arial', 'I', 10);
|
||
$intLines = max(2, (int)ceil($pdf->GetStringWidth(fxBibDistPrintPdfText($strLead)) / max(1, $fltInnerW)) + 1);
|
||
$fltBoxH = max(12, 4 + ($intLines * 4.5) + 3);
|
||
if ($pdf->GetY() + $fltBoxH > $pdf->GetPageHeight() - $fltBottom) {
|
||
$pdf->AddPage();
|
||
}
|
||
$fltY0 = $pdf->GetY();
|
||
$pdf->SetFillColor(232, 240, 254);
|
||
$pdf->Rect($fltLeft, $fltY0, $fltContentW, $fltBoxH, 'F');
|
||
$pdf->SetFillColor(47, 95, 208);
|
||
$pdf->Rect($fltLeft, $fltY0, 2.5, $fltBoxH, 'F');
|
||
$pdf->SetXY($fltLeft + 6, $fltY0 + 3.5);
|
||
$pdf->SetFont('Arial', 'I', 10);
|
||
$pdf->SetTextColor(40, 55, 90);
|
||
$pdf->MultiCell($fltInnerW, 4.5, fxBibDistPrintPdfText($strLead), 0, 'L');
|
||
$pdf->SetY($fltY0 + $fltBoxH + 5);
|
||
$pdf->SetTextColor(0, 0, 0);
|
||
$i++;
|
||
continue;
|
||
}
|
||
|
||
if ($strTag === 'h3' || $strTag === 'h2' || $strTag === 'h4') {
|
||
$intTip++;
|
||
$strTitleRaw = fxBibDistPrintDomPlainText($el);
|
||
$strTitle = $strTitleRaw;
|
||
$strNum = (string)$intTip;
|
||
if (preg_match('/^(\d+)\s*[\.\)\—\-–]\s*(.+)$/u', $strTitleRaw, $m)) {
|
||
$strNum = $m[1];
|
||
$strTitle = $m[2];
|
||
}
|
||
|
||
$bodyNode = null;
|
||
if (($i + 1) < $intN && strtolower($tabBlocks[$i + 1]->nodeName) === 'p') {
|
||
$bodyNode = $tabBlocks[$i + 1];
|
||
$i += 2;
|
||
} else {
|
||
$i++;
|
||
}
|
||
$strBodyPlain = $bodyNode ? fxBibDistPrintDomPlainText($bodyNode) : '';
|
||
|
||
$fltBadge = 12;
|
||
$fltPad = 4.5;
|
||
$fltInnerLeft = $fltLeft + 6 + $fltBadge + 5;
|
||
$fltInnerW = ($fltLeft + $fltContentW) - $fltPad - $fltInnerLeft;
|
||
|
||
$pdf->SetFont('Arial', 'B', 11);
|
||
$intTitleLines = max(1, (int)ceil($pdf->GetStringWidth(fxBibDistPrintPdfText($strTitle)) / max(1, $fltInnerW)));
|
||
$fltTitleH = $intTitleLines * 5.5;
|
||
$pdf->SetFont('Arial', '', 10);
|
||
$fltBodyH = 0;
|
||
if ($strBodyPlain !== '') {
|
||
$intBodyLines = max(1, (int)ceil($pdf->GetStringWidth(fxBibDistPrintPdfText($strBodyPlain)) / max(1, $fltInnerW)));
|
||
$fltBodyH = $intBodyLines * 4.8;
|
||
}
|
||
$fltCardH = max(24, $fltPad + $fltTitleH + 2 + $fltBodyH + $fltPad + 1);
|
||
|
||
if ($pdf->GetY() + $fltCardH > $pdf->GetPageHeight() - $fltBottom) {
|
||
$pdf->AddPage();
|
||
}
|
||
$fltY0 = $pdf->GetY();
|
||
|
||
$pdf->SetFillColor(247, 249, 252);
|
||
$pdf->SetDrawColor(200, 210, 228);
|
||
$pdf->Rect($fltLeft, $fltY0, $fltContentW, $fltCardH, 'FD');
|
||
$pdf->SetFillColor(47, 95, 208);
|
||
$pdf->Rect($fltLeft, $fltY0, 3.2, $fltCardH, 'F');
|
||
|
||
$fltBadgeX = $fltLeft + 7;
|
||
$fltBadgeY = $fltY0 + ($fltCardH - $fltBadge) / 2;
|
||
$pdf->SetFillColor(47, 95, 208);
|
||
$pdf->Rect($fltBadgeX, $fltBadgeY, $fltBadge, $fltBadge, 'F');
|
||
$pdf->SetTextColor(255, 255, 255);
|
||
$pdf->SetFont('Arial', 'B', 12);
|
||
$pdf->SetXY($fltBadgeX, $fltBadgeY + 2.8);
|
||
$pdf->Cell($fltBadge, 6, fxBibDistPrintPdfText($strNum), 0, 0, 'C');
|
||
|
||
$pdf->SetTextColor(25, 40, 70);
|
||
$pdf->SetFont('Arial', 'B', 11);
|
||
$pdf->SetXY($fltInnerLeft, $fltY0 + $fltPad);
|
||
$pdf->MultiCell($fltInnerW, 5.5, fxBibDistPrintPdfText($strTitle), 0, 'L');
|
||
|
||
if ($bodyNode) {
|
||
$pdf->SetTextColor(55, 65, 80);
|
||
$pdf->SetX($fltInnerLeft);
|
||
$pdf->SetLeftMargin($fltInnerLeft);
|
||
fxBibDistPrintWriteInline($pdf, $bodyNode, 4.8, 10);
|
||
$pdf->SetLeftMargin($fltLeft);
|
||
$pdf->Ln(2);
|
||
}
|
||
|
||
$pdf->SetY($fltY0 + $fltCardH + 3.5);
|
||
$pdf->SetTextColor(0, 0, 0);
|
||
$pdf->SetX($fltLeft);
|
||
continue;
|
||
}
|
||
|
||
// Image doc (ex. position du dossard) — centrée, largeur limitée.
|
||
if ($strTag === 'img') {
|
||
$strSrc = $el->getAttribute('src');
|
||
$strPath = fxBibDistPrintResolveDocImagePath($strSrc);
|
||
if ($strPath !== '') {
|
||
$pdf->Ln(1);
|
||
fxBibDistPrintWriteImage($pdf, $strPath, 85, true);
|
||
}
|
||
$i++;
|
||
continue;
|
||
}
|
||
|
||
// Autres blocs (ul/ol…) : rendu classique.
|
||
if ($strTag === 'p') {
|
||
// p après les cartes (rare) : texte simple.
|
||
$pdf->SetFont('Arial', '', 10);
|
||
$pdf->MultiCell($fltContentW, 5, fxBibDistPrintPdfText(fxBibDistPrintDomPlainText($el)), 0, 'L');
|
||
$pdf->Ln(2);
|
||
$i++;
|
||
continue;
|
||
}
|
||
|
||
fxBibDistPrintWriteHtml($pdf, $dom->saveHTML($el));
|
||
$i++;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — Rendu HTML simplifié (doc_html) vers FPDF.
|
||
* Tags supportés : h2–h4, p, ul/ol/li, strong/b, em/i, br, img, blockquote, article/div/span.
|
||
*/
|
||
function fxBibDistPrintWriteHtml($pdf, $strHtml) {
|
||
$strHtml = trim((string)$strHtml);
|
||
if ($strHtml === '') {
|
||
return;
|
||
}
|
||
if (!class_exists('DOMDocument', false)) {
|
||
$pdf->SetFont('Arial', '', 10);
|
||
$pdf->MultiCell(0, 5, fxBibDistPrintPdfText(strip_tags($strHtml)));
|
||
return;
|
||
}
|
||
|
||
$dom = new DOMDocument();
|
||
$blnPrev = libxml_use_internal_errors(true);
|
||
$dom->loadHTML(
|
||
'<?xml encoding="UTF-8"><div id="ms1-bib-dist-root">' . $strHtml . '</div>',
|
||
LIBXML_HTML_NODEFDTD
|
||
);
|
||
libxml_clear_errors();
|
||
libxml_use_internal_errors($blnPrev);
|
||
|
||
$root = $dom->getElementById('ms1-bib-dist-root');
|
||
if (!$root) {
|
||
$tabNodes = $dom->getElementsByTagName('div');
|
||
foreach ($tabNodes as $el) {
|
||
if ($el->getAttribute('id') === 'ms1-bib-dist-root') {
|
||
$root = $el;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (!$root) {
|
||
$pdf->SetFont('Arial', '', 10);
|
||
$pdf->MultiCell(0, 5, fxBibDistPrintPdfText(strip_tags($strHtml)));
|
||
return;
|
||
}
|
||
|
||
$fltLeft0 = method_exists($pdf, 'GetLeftMargin') ? $pdf->GetLeftMargin() : 10;
|
||
$fltTop0 = method_exists($pdf, 'GetTopMargin') ? $pdf->GetTopMargin() : 12;
|
||
|
||
$fnWalk = null;
|
||
$fnWalk = function ($node, $intListDepth = 0, $strListType = '') use ($pdf, &$fnWalk, &$fltLeft0, $fltTop0) {
|
||
if ($node->nodeType === XML_TEXT_NODE) {
|
||
$strText = preg_replace('/\s+/u', ' ', $node->nodeValue);
|
||
if ($strText !== null && trim($strText) !== '') {
|
||
$pdf->Write(5, fxBibDistPrintPdfText($strText));
|
||
}
|
||
return;
|
||
}
|
||
if ($node->nodeType !== XML_ELEMENT_NODE) {
|
||
return;
|
||
}
|
||
|
||
$strTag = strtolower($node->nodeName);
|
||
if ($strTag === 'br') {
|
||
$pdf->Ln(5);
|
||
return;
|
||
}
|
||
if ($strTag === 'img') {
|
||
$strSrc = $node->getAttribute('src');
|
||
$strPath = fxBibDistPrintResolveDocImagePath($strSrc);
|
||
if ($strPath !== '') {
|
||
$pdf->Ln(2);
|
||
fxBibDistPrintWriteImage($pdf, $strPath);
|
||
}
|
||
return;
|
||
}
|
||
|
||
$blnBlock = in_array($strTag, array('p', 'h2', 'h3', 'h4', 'li', 'blockquote', 'ul', 'ol'), true);
|
||
if ($blnBlock && $pdf->GetX() > $fltLeft0 + 0.5) {
|
||
$pdf->Ln(5);
|
||
}
|
||
|
||
if (in_array($strTag, array('h2', 'h3', 'h4'), true)) {
|
||
$fltSize = ($strTag === 'h2') ? 13 : (($strTag === 'h3') ? 11 : 10);
|
||
$pdf->SetFont('Arial', 'B', $fltSize);
|
||
if ($pdf->GetY() > $fltTop0 + 2) {
|
||
$pdf->Ln(2);
|
||
}
|
||
} elseif (in_array($strTag, array('strong', 'b'), true)) {
|
||
$pdf->SetFont('Arial', 'B', 10);
|
||
} elseif (in_array($strTag, array('em', 'i'), true)) {
|
||
$pdf->SetFont('Arial', 'I', 10);
|
||
} elseif ($strTag === 'blockquote') {
|
||
$pdf->SetFont('Arial', 'I', 10);
|
||
$fltLeft0 += 6;
|
||
$pdf->SetLeftMargin($fltLeft0);
|
||
$pdf->SetX($fltLeft0);
|
||
} elseif ($strTag === 'li') {
|
||
$pdf->SetFont('Arial', '', 10);
|
||
$strBullet = '- ';
|
||
// Compteur ol : index parmi les frères <li>
|
||
if ($strListType === 'ol' && $node->parentNode) {
|
||
$intIdx = 1;
|
||
foreach ($node->parentNode->childNodes as $sib) {
|
||
if ($sib === $node) {
|
||
break;
|
||
}
|
||
if ($sib->nodeType === XML_ELEMENT_NODE && strtolower($sib->nodeName) === 'li') {
|
||
$intIdx++;
|
||
}
|
||
}
|
||
$strBullet = $intIdx . '. ';
|
||
}
|
||
$pdf->SetX($fltLeft0 + (6 * max(0, $intListDepth)));
|
||
$pdf->Write(5, fxBibDistPrintPdfText($strBullet));
|
||
} elseif (in_array($strTag, array('p', 'div', 'span', 'article'), true)) {
|
||
$pdf->SetFont('Arial', '', 10);
|
||
}
|
||
|
||
$strChildList = $strListType;
|
||
$intChildDepth = $intListDepth;
|
||
if ($strTag === 'ul') {
|
||
$strChildList = 'ul';
|
||
$intChildDepth = $intListDepth + 1;
|
||
} elseif ($strTag === 'ol') {
|
||
$strChildList = 'ol';
|
||
$intChildDepth = $intListDepth + 1;
|
||
}
|
||
|
||
foreach ($node->childNodes as $child) {
|
||
$fnWalk($child, $intChildDepth, $strChildList);
|
||
}
|
||
|
||
if ($strTag === 'blockquote') {
|
||
$fltLeft0 -= 6;
|
||
$pdf->SetLeftMargin($fltLeft0);
|
||
}
|
||
if ($blnBlock) {
|
||
$pdf->Ln(5);
|
||
$pdf->SetX($fltLeft0);
|
||
}
|
||
if (in_array($strTag, array('h2', 'h3', 'h4', 'strong', 'b', 'em', 'i', 'blockquote', 'li', 'p'), true)) {
|
||
$pdf->SetFont('Arial', '', 10);
|
||
}
|
||
};
|
||
|
||
foreach ($root->childNodes as $child) {
|
||
$fnWalk($child, 0, '');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — Dessine le QR résultats événement (kc.php?t=eve) centré.
|
||
* Affiche ms1.ca sous le QR (pas l'URL technique).
|
||
*/
|
||
function fxBibDistPrintDrawEventQr($pdf, $int_eve_id, $strCaption = '') {
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($int_eve_id <= 0 || !function_exists('fxKcEveResultatsQrPngBinary')) {
|
||
return;
|
||
}
|
||
$binPng = fxKcEveResultatsQrPngBinary($int_eve_id, null, 12, true);
|
||
if ($binPng === false || $binPng === '') {
|
||
return;
|
||
}
|
||
$strTmp = tempnam(sys_get_temp_dir(), 'bibqr_');
|
||
if ($strTmp === false) {
|
||
return;
|
||
}
|
||
@unlink($strTmp);
|
||
$strTmpPng = $strTmp . '.png';
|
||
if (@file_put_contents($strTmpPng, $binPng) === false) {
|
||
return;
|
||
}
|
||
|
||
$fltBottom = method_exists($pdf, 'GetBreakMargin') ? $pdf->GetBreakMargin() : 18;
|
||
$fltSize = 95;
|
||
|
||
$strCaption = trim((string)$strCaption);
|
||
if ($strCaption !== '') {
|
||
$pdf->Ln(6);
|
||
$pdf->SetFont('Arial', 'B', 13);
|
||
$pdf->SetTextColor(25, 40, 70);
|
||
$pdf->MultiCell(0, 7, fxBibDistPrintPdfText($strCaption), 0, 'C');
|
||
$pdf->SetTextColor(0, 0, 0);
|
||
$pdf->Ln(4);
|
||
} else {
|
||
$pdf->Ln(10);
|
||
}
|
||
|
||
if ($pdf->GetY() + $fltSize + 16 > $pdf->GetPageHeight() - $fltBottom) {
|
||
$pdf->AddPage();
|
||
}
|
||
$fltX = ($pdf->GetPageWidth() - $fltSize) / 2;
|
||
$pdf->Image($strTmpPng, $fltX, $pdf->GetY(), $fltSize, $fltSize);
|
||
$pdf->Ln($fltSize + 6);
|
||
|
||
$pdf->SetFont('Arial', 'B', 16);
|
||
$pdf->SetTextColor(47, 95, 208);
|
||
$pdf->MultiCell(0, 8, fxBibDistPrintPdfText('ms1.ca'), 0, 'C');
|
||
$pdf->SetTextColor(0, 0, 0);
|
||
|
||
@unlink($strTmpPng);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — 3 pages d'intro (doc_page) avant les listes d'épreuves.
|
||
*/
|
||
function fxBibOutputDistPrintIntroPages($pdf, $int_eve_id, $strLangue = 'fr') {
|
||
// Aligner fxDocLangue() sur la langue du PDF.
|
||
$GLOBALS['strLangue'] = ($strLangue === 'en') ? 'en' : 'fr';
|
||
|
||
if (!function_exists('fxDocSchemaReady') || !fxDocSchemaReady()) {
|
||
return;
|
||
}
|
||
|
||
$pdf->blnIntroMode = true;
|
||
$pdf->eprTitle = '';
|
||
$pdf->documentSubtitle = '';
|
||
$strDefaultDocTitle = fxBibTexte('bib_v4_dist_print_title', 0);
|
||
|
||
// Marges flyer : place pour bandeau (sous-titre majuscule) + logo pied de page.
|
||
$pdf->SetMargins(12, 46, 12);
|
||
$pdf->SetAutoPageBreak(true, 18);
|
||
|
||
$intPageBeforeIntro = (int)$pdf->PageNo();
|
||
foreach (fxBibDistPrintIntroPageClefs() as $strClef) {
|
||
$row = function_exists('fxDocGetPageRow') ? fxDocGetPageRow($strClef, 0) : array();
|
||
$strTitre = trim((string)($row['doc_titre'] ?? ''));
|
||
$strSous = trim((string)($row['doc_sous_titre'] ?? ''));
|
||
$strHtml = trim((string)($row['doc_html'] ?? ''));
|
||
if ($strTitre === '' && $strHtml === '') {
|
||
continue;
|
||
}
|
||
$pdf->documentTitle = ($strTitre !== '') ? $strTitre : $strClef;
|
||
$pdf->documentSubtitle = $strSous;
|
||
$pdf->AddPage();
|
||
|
||
// Page QR : en-tête + invite + gros QR + ms1.ca (pas de cartes flyer).
|
||
if ($strClef === 'bib_dist_print_qr') {
|
||
$strCaption = trim(html_entity_decode(strip_tags($strHtml), ENT_QUOTES, 'UTF-8'));
|
||
fxBibDistPrintDrawEventQr($pdf, $int_eve_id, $strCaption);
|
||
continue;
|
||
}
|
||
|
||
fxBibDistPrintWriteIntroFlyer($pdf, $strHtml);
|
||
}
|
||
$pdf->intIntroPageCount = max(0, (int)$pdf->PageNo() - $intPageBeforeIntro);
|
||
|
||
$pdf->blnIntroMode = false;
|
||
$pdf->documentTitle = $strDefaultDocTitle;
|
||
$pdf->documentSubtitle = '';
|
||
$pdf->eprTitle = '';
|
||
$pdf->SetMargins(10, 12, 10);
|
||
$pdf->SetAutoPageBreak(true, 18);
|
||
}
|
||
|
||
/** MSIN-4433 — Génère et envoie le PDF (format lettre). */
|
||
function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = '') {
|
||
global $objDatabase;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($int_eve_id <= 0) {
|
||
http_response_code(400);
|
||
exit;
|
||
}
|
||
|
||
$tabEvent = $objDatabase->fxGetRow("SELECT * FROM inscriptions_evenements WHERE eve_id = $int_eve_id LIMIT 1");
|
||
if (!is_array($tabEvent)) {
|
||
http_response_code(404);
|
||
exit;
|
||
}
|
||
|
||
$strEventTitle = trim((string)($tabEvent['eve_nom_' . $strLangue] ?? ''));
|
||
if ($strEventTitle === '') {
|
||
$strEventTitle = trim((string)($tabEvent['eve_nom_fr'] ?? ''));
|
||
}
|
||
|
||
$strPrintedAt = fxBibFormatDistPrintDateTime('', $strLangue);
|
||
if (trim((string)$strPrintedBy) === '') {
|
||
$strPrintedBy = fxBibGetCurrentPromoteurDisplayName();
|
||
}
|
||
$strFooter = sprintf(
|
||
fxBibTexte('bib_v4_dist_print_footer', 0),
|
||
$strPrintedAt,
|
||
$strPrintedBy
|
||
);
|
||
|
||
$tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue);
|
||
|
||
$strDocRoot = $_SERVER['DOCUMENT_ROOT'] ?? dirname(__DIR__);
|
||
require_once($strDocRoot . '/fpdf182/fpdf.php');
|
||
|
||
if (!class_exists('BibDistPrintPdf', false)) {
|
||
class BibDistPrintPdf extends FPDF {
|
||
public $footerText = '';
|
||
public $pageText = 'Page %s / %s';
|
||
public $eventTitle = '';
|
||
public $documentTitle = '';
|
||
public $documentSubtitle = '';
|
||
public $eprTitle = '';
|
||
/** MSIN-4471 — Pages intro : bandeau flyer, pas de sous-titre épreuve. */
|
||
public $blnIntroMode = false;
|
||
/** MSIN-4471 — Nb de pages intro (pagination listes démarre à 1). */
|
||
public $intIntroPageCount = 0;
|
||
|
||
/** MSIN-4471 — Accès public aux marges (protégées dans FPDF 1.82). */
|
||
function GetLeftMargin() {
|
||
return $this->lMargin;
|
||
}
|
||
function GetRightMargin() {
|
||
return $this->rMargin;
|
||
}
|
||
function GetTopMargin() {
|
||
return $this->tMargin;
|
||
}
|
||
function GetBreakMargin() {
|
||
return $this->bMargin;
|
||
}
|
||
|
||
function Header() {
|
||
if ($this->blnIntroMode) {
|
||
$fltW = $this->GetPageWidth();
|
||
$strSous = trim((string)$this->documentSubtitle);
|
||
$blnHasSous = ($strSous !== '');
|
||
$fltBandH = $blnHasSous ? 38 : 30;
|
||
|
||
// Bandeau flyer (bleu MS1 + filet or).
|
||
$this->SetFillColor(47, 95, 208);
|
||
$this->Rect(0, 0, $fltW, $fltBandH, 'F');
|
||
$this->SetFillColor(255, 193, 7);
|
||
$this->Rect(0, $fltBandH, $fltW, 2, 'F');
|
||
|
||
$fltTextX = 12;
|
||
$strLogo = function_exists('fxBibDistPrintMs1LogoPath') ? fxBibDistPrintMs1LogoPath() : '';
|
||
if ($strLogo !== '') {
|
||
$fltLogoW = 34;
|
||
$this->Image($strLogo, 10, 8, $fltLogoW);
|
||
$fltTextX = 10 + $fltLogoW + 5;
|
||
}
|
||
|
||
$fltTextW = $fltW - $fltTextX - 10;
|
||
$this->SetTextColor(255, 255, 255);
|
||
$this->SetXY($fltTextX, 5);
|
||
$this->SetFont('Arial', 'B', 13);
|
||
$this->Cell($fltTextW, 6, fxBibDistPrintPdfText($this->eventTitle), 0, 2, 'L');
|
||
$this->SetFont('Arial', 'B', 11);
|
||
$this->Cell($fltTextW, 5.5, fxBibDistPrintPdfText($this->documentTitle), 0, 2, 'L');
|
||
if ($blnHasSous) {
|
||
$strSousUp = function_exists('mb_strtoupper')
|
||
? mb_strtoupper($strSous, 'UTF-8')
|
||
: strtoupper($strSous);
|
||
$this->SetFont('Arial', 'B', 11);
|
||
$this->SetTextColor(255, 255, 255);
|
||
$this->MultiCell($fltTextW, 5, fxBibDistPrintPdfText($strSousUp), 0, 'L');
|
||
}
|
||
$this->SetTextColor(0, 0, 0);
|
||
$this->SetY($fltBandH + 6);
|
||
return;
|
||
}
|
||
|
||
$this->SetFont('Arial', 'B', 14);
|
||
$this->Cell(0, 8, fxBibDistPrintPdfText($this->eventTitle), 0, 1, 'C');
|
||
$this->SetFont('Arial', '', 10);
|
||
$this->Cell(0, 6, fxBibDistPrintPdfText($this->documentTitle), 0, 1, 'C');
|
||
$this->Ln(2);
|
||
if ($this->eprTitle !== '') {
|
||
$this->SetFont('Arial', 'B', 11);
|
||
$this->Cell(0, 7, fxBibDistPrintPdfText($this->eprTitle), 0, 1, 'L');
|
||
$this->Ln(1);
|
||
}
|
||
}
|
||
|
||
function Footer() {
|
||
$strLogo = function_exists('fxBibDistPrintMs1LogoPath') ? fxBibDistPrintMs1LogoPath() : '';
|
||
$fltPageW = $this->GetPageWidth();
|
||
$fltPageH = $this->GetPageHeight();
|
||
$fltLogoW = 22;
|
||
$fltLogoH = $fltLogoW * (101 / 355); // ~6.3 mm (ratio logo MS1)
|
||
$fltGap = 4;
|
||
$fltPageNumW = 32;
|
||
$blnShowPage = !$this->blnIntroMode;
|
||
|
||
$fltLogoX = $fltPageW - $this->rMargin - $fltLogoW;
|
||
$fltLogoY = $fltPageH - 9.5;
|
||
$fltPageNumX = ($strLogo !== '' && $blnShowPage)
|
||
? ($fltLogoX - $fltGap - $fltPageNumW)
|
||
: (($strLogo !== '')
|
||
? ($fltLogoX - $fltGap)
|
||
: ($fltPageW - $this->rMargin - ($blnShowPage ? $fltPageNumW : 0)));
|
||
$fltTextW = max(30, ($blnShowPage ? $fltPageNumX : $fltLogoX - $fltGap) - $this->lMargin - 2);
|
||
|
||
// Logo : fond noir pour garder le contraste (logo blanc sur noir).
|
||
if ($strLogo !== '') {
|
||
$this->SetFillColor(0, 0, 0);
|
||
$this->Rect($fltLogoX - 0.8, $fltLogoY - 0.8, $fltLogoW + 1.6, $fltLogoH + 1.6, 'F');
|
||
$this->Image($strLogo, $fltLogoX, $fltLogoY, $fltLogoW);
|
||
}
|
||
|
||
$this->SetY(-11);
|
||
$this->SetFont('Arial', 'I', 7);
|
||
$this->SetTextColor(90, 90, 90);
|
||
$this->SetX($this->lMargin);
|
||
$this->Cell($fltTextW, 4, fxBibDistPrintPdfText($this->footerText), 0, 0, 'L');
|
||
|
||
// Pagination : absente sur les pages intro ; page 1 = 1re page de listes.
|
||
if ($blnShowPage) {
|
||
$intCur = max(1, $this->PageNo() - (int)$this->intIntroPageCount);
|
||
$strPage = sprintf($this->pageText, $intCur, '{nb}');
|
||
$this->SetXY($fltPageNumX, -11);
|
||
$this->Cell($fltPageNumW, 4, fxBibDistPrintPdfText($strPage), 0, 0, 'R');
|
||
}
|
||
$this->SetTextColor(0, 0, 0);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4471 — {nb} = pages de listes seulement (hors intro).
|
||
*/
|
||
protected function _putpage($n) {
|
||
if (!empty($this->AliasNbPages) && (int)$this->intIntroPageCount > 0) {
|
||
$intNbList = max(0, $this->page - (int)$this->intIntroPageCount);
|
||
$this->pages[$n] = str_replace($this->AliasNbPages, (string)$intNbList, $this->pages[$n]);
|
||
$strSaved = $this->AliasNbPages;
|
||
$this->AliasNbPages = '';
|
||
parent::_putpage($n);
|
||
$this->AliasNbPages = $strSaved;
|
||
return;
|
||
}
|
||
parent::_putpage($n);
|
||
}
|
||
}
|
||
}
|
||
|
||
$pdf = new BibDistPrintPdf('P', 'mm', 'letter');
|
||
$pdf->footerText = $strFooter;
|
||
$pdf->pageText = fxBibTexte('bib_v4_dist_print_page', 0);
|
||
$pdf->eventTitle = fxBibDistPrintTruncate($strEventTitle, 80);
|
||
$pdf->documentTitle = fxBibTexte('bib_v4_dist_print_title', 0);
|
||
$pdf->SetMargins(10, 12, 10);
|
||
$pdf->SetAutoPageBreak(true, 18);
|
||
$pdf->AliasNbPages();
|
||
|
||
// MSIN-4471 — Pages d'explication (doc) avant les tableaux d'épreuves.
|
||
fxBibOutputDistPrintIntroPages($pdf, $int_eve_id, $strLangue);
|
||
|
||
// MSIN-4471 — Feuille bénévole : recherche par nom, puis dossard à remettre.
|
||
// Ordre : ☐ | Nom, Prénom | Dossard | Sexe | questions
|
||
$fltPageW = $pdf->GetPageWidth() - 20;
|
||
$fltColCheck = 10;
|
||
$fltColBib = 28;
|
||
$fltColSexe = 12;
|
||
$fltFixedW = $fltColCheck + $fltColBib + $fltColSexe;
|
||
$fltRowH = 8;
|
||
$fltHeadH = 8;
|
||
$fltBottom = method_exists($pdf, 'GetBreakMargin') ? $pdf->GetBreakMargin() : 14;
|
||
$blnHasPrintedEpreuve = false;
|
||
|
||
foreach ($tabPanel['epreuves'] as $tabEpr) {
|
||
$epr_id = (int)($tabEpr['epr_id'] ?? 0);
|
||
if ($epr_id <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$tabEprRow = $objDatabase->fxGetRow("SELECT * FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1");
|
||
if (!is_array($tabEprRow)) {
|
||
continue;
|
||
}
|
||
|
||
// MSIN-4471 — Tri nom/prénom forcé dans fxBibGetParticipantsForDistPrint (args ignorés).
|
||
$tabParticipants = fxBibGetParticipantsForDistPrint($epr_id, 'ba:2', '', $strLangue);
|
||
// MSIN-4433 — Épreuve sans dossard assigné : ne pas imprimer la section.
|
||
if (empty($tabParticipants)) {
|
||
continue;
|
||
}
|
||
|
||
$tabSelectedQue = $tabEpr['selected'] ?? [];
|
||
$tabQueCols = [];
|
||
foreach ($tabEpr['questions'] as $opt) {
|
||
if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) {
|
||
$intQueId = (int)$m[1];
|
||
if (in_array($intQueId, $tabSelectedQue, true)) {
|
||
$tabQueCols[] = [
|
||
'que_id' => $intQueId,
|
||
'label' => (string)($opt['label'] ?? ('Q' . $intQueId)),
|
||
];
|
||
}
|
||
}
|
||
}
|
||
// MSIN-4471 — Max 3 questions affichées (lisibilité feuille bénévole).
|
||
if (count($tabQueCols) > fxBibDistPrintMaxQuestions()) {
|
||
$tabQueCols = array_slice($tabQueCols, 0, fxBibDistPrintMaxQuestions());
|
||
}
|
||
|
||
$intNbQ = count($tabQueCols);
|
||
$fltNameW = 78;
|
||
$fltQTotal = max(0, $fltPageW - $fltFixedW - $fltNameW);
|
||
if ($intNbQ === 0) {
|
||
$fltNameW = $fltPageW - $fltFixedW;
|
||
$fltQEach = 0;
|
||
} else {
|
||
$fltQEach = $fltQTotal / $intNbQ;
|
||
}
|
||
|
||
$pdf->eprTitle = fxBibDistPrintTruncate($tabEpr['epr_label'] ?? '', 90);
|
||
$pdf->AddPage();
|
||
$blnHasPrintedEpreuve = true;
|
||
|
||
$tabAnswers = fxBibGetDistPrintQuestionAnswers($epr_id, $tabSelectedQue, $tabParticipants, $strLangue);
|
||
|
||
$fnDrawTableHeader = function () use ($pdf, $fltColCheck, $fltColBib, $fltNameW, $fltColSexe, $fltQEach, $tabQueCols, $intNbQ, $fltHeadH) {
|
||
$pdf->SetFont('Arial', 'B', 10);
|
||
$pdf->SetFillColor(220, 220, 220);
|
||
// Case remise | Nom (recherche) | Dossard | Sexe | …
|
||
$pdf->Cell($fltColCheck, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_check', 0)), 1, 0, 'C', true);
|
||
$pdf->Cell($fltNameW, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_nom_prenom', 0)), 1, 0, 'L', true);
|
||
$pdf->Cell($fltColBib, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_bib', 0)), 1, 0, 'C', true);
|
||
$pdf->Cell($fltColSexe, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_sexe', 0)), 1, $intNbQ === 0 ? 1 : 0, 'C', true);
|
||
foreach ($tabQueCols as $i => $col) {
|
||
$blnLast = ($i === $intNbQ - 1);
|
||
$pdf->Cell($fltQEach, $fltHeadH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($col['label'], 18)), 1, $blnLast ? 1 : 0, 'L', true);
|
||
}
|
||
};
|
||
|
||
$fnDrawTableHeader();
|
||
|
||
$intRow = 0;
|
||
foreach ($tabParticipants as $row) {
|
||
// Nouvelle page + répéter l'en-tête de colonnes (feuille bénévole).
|
||
if ($pdf->GetY() + $fltRowH > $pdf->GetPageHeight() - $fltBottom) {
|
||
$pdf->AddPage();
|
||
$fnDrawTableHeader();
|
||
}
|
||
|
||
$strKey = fxBibDistPrintAnswerKey($row);
|
||
$strNom = trim((string)($row['par_nom'] ?? ''));
|
||
$strPrenom = trim((string)($row['par_prenom'] ?? ''));
|
||
$strNomPrenom = $strNom;
|
||
if ($strPrenom !== '') {
|
||
$strNomPrenom .= ($strNom !== '' ? ', ' : '') . $strPrenom;
|
||
}
|
||
|
||
$blnAlt = ($intRow % 2) === 1;
|
||
if ($blnAlt) {
|
||
$pdf->SetFillColor(245, 245, 245);
|
||
} else {
|
||
$pdf->SetFillColor(255, 255, 255);
|
||
}
|
||
$blnFill = true;
|
||
|
||
// Case à cocher (vide) pour marquer la remise.
|
||
$pdf->SetFont('Arial', '', 11);
|
||
$pdf->Cell($fltColCheck, $fltRowH, '', 1, 0, 'C', $blnFill);
|
||
|
||
// Nom, Prénom — colonne de recherche principale.
|
||
$pdf->SetFont('Arial', 'B', 11);
|
||
$pdf->Cell($fltNameW, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strNomPrenom, 42)), 1, 0, 'L', $blnFill);
|
||
|
||
// Dossard — numéro à remettre.
|
||
$pdf->SetFont('Arial', 'B', 14);
|
||
$pdf->Cell($fltColBib, $fltRowH, fxBibDistPrintPdfText((string)(int)($row['no_bib'] ?? 0)), 1, 0, 'C', $blnFill);
|
||
|
||
$pdf->SetFont('Arial', '', 11);
|
||
$pdf->Cell($fltColSexe, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue)), 1, $intNbQ === 0 ? 1 : 0, 'C', $blnFill);
|
||
|
||
foreach ($tabQueCols as $i => $col) {
|
||
$intQueId = (int)$col['que_id'];
|
||
$strAns = $tabAnswers[$strKey][$intQueId] ?? '';
|
||
$blnLast = ($i === $intNbQ - 1);
|
||
$pdf->SetFont('Arial', '', 10);
|
||
$pdf->Cell($fltQEach, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strAns, 20)), 1, $blnLast ? 1 : 0, 'L', $blnFill);
|
||
}
|
||
|
||
$intRow++;
|
||
}
|
||
|
||
$pdf->Ln(4);
|
||
}
|
||
|
||
if (!$blnHasPrintedEpreuve && $pdf->PageNo() < 1) {
|
||
$pdf->AddPage();
|
||
}
|
||
|
||
$strFilename = 'distribution-dossards-' . $int_eve_id . '.pdf';
|
||
$pdf->Output('I', $strFilename);
|
||
}
|
||
|
||
/** MSIN-4433 — Coquille panneau impression (chargement AJAX). */
|
||
function renderBibDistPrintPanelShell($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();
|
||
?>
|
||
<div id="bib-dist-print-panel"
|
||
class="bib-dist-print-panel bib-anomalies-panel bib-tool-panel epr-block is-collapsed"
|
||
data-bib-tool="dist_print"
|
||
data-eve-id="<?php echo $int_eve_id; ?>"
|
||
data-bib-dist-print-deferred="1">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_dist_print_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_dist_print_title'); ?>
|
||
<?php
|
||
// MSIN-4471 — Doc pages intro PDF.
|
||
if (function_exists('fxDocRenderTrigger')) {
|
||
echo fxDocRenderTrigger('bib_v4_dist_print_doc');
|
||
if (function_exists('fxAdminDocButton')) {
|
||
echo fxAdminDocButton('bib_v4_dist_print_doc');
|
||
}
|
||
}
|
||
?>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-dist-print-content">
|
||
<div class="ms1-loader ms1-loader--inline" role="status" aria-live="polite" aria-busy="true">
|
||
<img class="ms1-loader__runner"
|
||
src="<?php echo fxBibEsc($strRunnerSrc); ?>"
|
||
alt=""
|
||
role="presentation"
|
||
decoding="async">
|
||
<span class="ms1-loader__label"><?php echo fxBibEsc($strWait); ?></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** MSIN-4433 — Panneau impression PDF (formulaire + choix questions). */
|
||
function renderBibDistPrintPanel($int_eve_id, $strLangue = 'fr', $tabPanel = null) {
|
||
global $vDomaine;
|
||
|
||
$int_eve_id = (int)$int_eve_id;
|
||
if ($tabPanel === null) {
|
||
$tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue);
|
||
}
|
||
|
||
$tabMeta = $tabPanel['meta'] ?? [];
|
||
$tabEpreuves = $tabPanel['epreuves'] ?? [];
|
||
$intMaxQ = fxBibDistPrintMaxQuestions();
|
||
$strPrintUrl = $vDomaine . '/bib_dist_print.php';
|
||
|
||
ob_start();
|
||
?>
|
||
<div id="bib-dist-print-panel"
|
||
class="bib-dist-print-panel bib-anomalies-panel bib-tool-panel epr-block is-collapsed"
|
||
data-bib-tool="dist_print"
|
||
data-eve-id="<?php echo $int_eve_id; ?>"
|
||
data-bib-dist-print-loaded="1"
|
||
data-max-questions="<?php echo (int)$intMaxQ; ?>">
|
||
<div class="epr-header bib-anomalies-header">
|
||
<span class="epr-header-label bib-anomalies-header-label">
|
||
<?php echo fxBibEsc(fxBibTexte('bib_v4_dist_print_title', 0)); ?>
|
||
<?php echo fxBibAideButton('bib_v4_dist_print_title'); ?>
|
||
<?php
|
||
// MSIN-4471 — Doc pages intro PDF.
|
||
if (function_exists('fxDocRenderTrigger')) {
|
||
echo fxDocRenderTrigger('bib_v4_dist_print_doc');
|
||
if (function_exists('fxAdminDocButton')) {
|
||
echo fxAdminDocButton('bib_v4_dist_print_doc');
|
||
}
|
||
}
|
||
?>
|
||
</span>
|
||
<?php echo fxBibBlockCollapseToggle($strLangue, true); ?>
|
||
</div>
|
||
<div class="epr-content bib-dist-print-content">
|
||
<p class="bib-dist-print-last text-muted small mb-3">
|
||
<?php
|
||
if (!empty($tabMeta['at'])) {
|
||
echo fxBibEsc(sprintf(
|
||
fxBibTexte('bib_v4_dist_print_last', 0),
|
||
fxBibFormatDistPrintDateTime($tabMeta['at'], $strLangue),
|
||
$tabMeta['by'] !== '' ? $tabMeta['by'] : '—'
|
||
));
|
||
} else {
|
||
fxBibTexteTrad('bib_v4_dist_print_last_none', 1);
|
||
}
|
||
?>
|
||
</p>
|
||
<p class="bib-dist-print-hint text-muted small mb-3">
|
||
<?php echo fxBibEsc(fxBibMsg('bib_v4_dist_print_max_questions', $intMaxQ)); ?>
|
||
</p>
|
||
|
||
<form class="bib-dist-print-form"
|
||
method="post"
|
||
action="<?php echo fxBibEsc($strPrintUrl); ?>"
|
||
target="_blank"
|
||
data-print-url="<?php echo fxBibEsc($strPrintUrl); ?>">
|
||
<input type="hidden" name="eve_id" value="<?php echo $int_eve_id; ?>">
|
||
<input type="hidden" name="csrf_token" value="<?php echo fxBibEsc(fxBibCsrfToken()); ?>">
|
||
<input type="hidden" name="lang" value="<?php echo fxBibEsc($strLangue); ?>">
|
||
|
||
<?php foreach ($tabEpreuves as $tabEpr) {
|
||
$epr_id = (int)($tabEpr['epr_id'] ?? 0);
|
||
$tabQuestions = $tabEpr['questions'] ?? [];
|
||
$tabSelected = $tabEpr['selected'] ?? [];
|
||
?>
|
||
<section class="bib-dist-print-epr" data-epr-id="<?php echo $epr_id; ?>">
|
||
<h3 class="bib-dist-print-epr-title">
|
||
<?php echo fxBibEsc($tabEpr['epr_label'] ?? ''); ?>
|
||
<span class="text-muted small">(<?php echo (int)($tabEpr['avec_bib'] ?? 0); ?>)</span>
|
||
</h3>
|
||
<?php if (empty($tabQuestions)) { ?>
|
||
<p class="text-muted small bib-dist-print-no-questions">
|
||
<?php fxBibTexteTrad('bib_v4_dist_print_no_questions', 1); ?>
|
||
</p>
|
||
<?php } else { ?>
|
||
<fieldset class="bib-dist-print-questions">
|
||
<legend class="sr-only"><?php echo fxBibEsc(fxBibTexte('bib_v4_dist_print_questions', 0)); ?></legend>
|
||
<span class="bib-dist-print-questions-label small text-muted d-block mb-1">
|
||
<?php fxBibTexteTrad('bib_v4_dist_print_questions', 1); ?>
|
||
</span>
|
||
<ul class="bib-dist-print-question-list list-unstyled mb-0">
|
||
<?php foreach ($tabQuestions as $opt) {
|
||
if (!preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) {
|
||
continue;
|
||
}
|
||
$intQueId = (int)$m[1];
|
||
$blnChecked = in_array($intQueId, $tabSelected, true);
|
||
?>
|
||
<li class="bib-dist-print-question-item">
|
||
<label class="bib-dist-print-question-label">
|
||
<input type="checkbox"
|
||
class="bib-dist-print-question-cb"
|
||
name="dist_print[<?php echo $epr_id; ?>][]"
|
||
value="<?php echo $intQueId; ?>"
|
||
<?php echo $blnChecked ? 'checked' : ''; ?>>
|
||
<span><?php echo fxBibEsc($opt['label'] ?? ''); ?></span>
|
||
</label>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
</fieldset>
|
||
<?php } ?>
|
||
</section>
|
||
<?php } ?>
|
||
|
||
<div class="bib-dist-print-actions mt-3">
|
||
<button type="submit" class="btn btn-primary btn-sm bib-dist-print-submit">
|
||
<?php fxBibTexteTrad('bib_v4_dist_print_generate', 1); ?>
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|