10566 lines
442 KiB
PHP
10566 lines
442 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 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') {
|
||
$sqlUpdate .= "SET no_bib = '', par_date_bib = null";
|
||
// $sqlUpdate .= "SET no_bib = ''";
|
||
} else {
|
||
if($tabInscriptions[$i]['par_date_bib'] == null){
|
||
$sqlUpdate .= "SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "'";
|
||
} else{
|
||
$sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "'";
|
||
// $sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "', par_maj = '" . fxGetDateTime() . "'";
|
||
// $sqlUpdate .= "SET no_bib = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "', par_modification_promoteur = 1, par_maj = '" . fxGetDateTime() . "'";
|
||
}
|
||
}
|
||
|
||
$sqlUpdate .= " WHERE par_id = " . $tabInscriptions[$i]['par_id'] . " AND is_cancelled = 0";
|
||
$qryUpdate = $objDatabase->fxQuery($sqlUpdate);
|
||
|
||
if (!$qryUpdate) {
|
||
fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']);
|
||
} 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). "' WHERE par_id = " . $intParEqBatch;
|
||
} else{
|
||
$sqlUpdatePart = "UPDATE resultats_participants SET no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . $intParEqBatch;
|
||
// $sqlUpdatePart = "UPDATE resultats_participants SET par_maj = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']);
|
||
// $sqlUpdatePart = "UPDATE resultats_participants SET par_maj = '" . fxGetDateTime() . "', par_modification_promoteur = 1, no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']);
|
||
}
|
||
$qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart);
|
||
if (!$qryUpdatePart) {
|
||
fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']);
|
||
} 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' => 'Épreuves solo sans séquence : choisissez Début et Fin (ou Qté). Les dossards sont assignés sans créer de séquence. Le Go reste disponible même si la quantité n\'est pas juste.', 'en' => 'Solo races without sequences: choose Start and End (or Qty). Bibs are assigned without creating a sequence. 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_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 if (!empty($_SESSION['usa_id'])) { ?>
|
||
<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 } ?>
|
||
<?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 — 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>
|
||
|
||
<section class="bib-workspace-panel bib-ui-hidden" data-bib-workspace-panel="operations">
|
||
<div class="bib-workspace-panel-heading">
|
||
<p><?php fxBibTexteTrad('bib_v5_modes_intro', 1); ?></p>
|
||
</div>
|
||
<nav class="bib-tool-nav bib-tool-nav--operations" aria-label="<?php echo fxBibEsc(fxBibTexte('bib_v5_workspace_operations', 0)); ?>">
|
||
<?php if (fxBibGlobalBatchToolIsAvailable($int_eve_id, $tabEpreuves)) {
|
||
echo renderBibToolNavBtn('global_batch', 'bib_v4_global_batch_title');
|
||
} ?>
|
||
</nav>
|
||
</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).
|
||
*/
|
||
function renderBibGlobalBatchPanelFree($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('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
|
||
* Assigne un dossard à un participant à l'achat (pools epr_bib_auto = 1).
|
||
* Réutilise fxFindNextBatchBib / fxApplyBatchParticipantBib et la logique équipe du batch.
|
||
*/
|
||
function fxAssignAutoBibForParticipant($epr_id, $par_id) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = intval($epr_id);
|
||
$par_id = intval($par_id);
|
||
|
||
if ($epr_id <= 0 || $par_id <= 0) {
|
||
return ['success' => false, 'message' => 'paramètres invalides'];
|
||
}
|
||
|
||
if (!fxIsBibAutoActive($epr_id)) {
|
||
return ['success' => false, 'skipped' => true, 'message' => 'auto inactif'];
|
||
}
|
||
|
||
$tabRanges = fxGetRangesForBatchAssign($epr_id, fxGetAutoBibRangeIds($epr_id));
|
||
|
||
if (empty($tabRanges)) {
|
||
return ['success' => false, 'message' => 'aucune plage auto'];
|
||
}
|
||
|
||
$p = fxLoadParticipantForAutoBib($epr_id, $par_id);
|
||
|
||
if (!$p) {
|
||
return ['success' => false, 'message' => 'participant introuvable'];
|
||
}
|
||
|
||
if (in_array((int)$p['rol_id'], [3, 4], true)) {
|
||
return ['success' => false, 'skipped' => true, 'message' => 'rôle exclu'];
|
||
}
|
||
|
||
$currentBib = trim((string)($p['no_bib'] ?? ''));
|
||
|
||
if ($currentBib !== '' && $currentBib !== '0') {
|
||
return [
|
||
'success' => true,
|
||
'skipped' => true,
|
||
'no_bib' => (int)$currentBib,
|
||
];
|
||
}
|
||
|
||
$sqlEpreuve = "
|
||
SELECT epr_equipe, epr_bib_team_mode
|
||
FROM inscriptions_epreuves
|
||
WHERE epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
$tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve);
|
||
|
||
$isTeamEvent = $tabEpreuve && (int)$tabEpreuve['epr_equipe'] === 1;
|
||
$teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1);
|
||
|
||
if ($teamMode <= 0) {
|
||
$teamMode = 1;
|
||
}
|
||
|
||
$teamKey = fxGetBatchTeamKey($p);
|
||
$foundBib = null;
|
||
$teamNumber = 0;
|
||
$usedBib = [];
|
||
|
||
if ($isTeamEvent && $teamMode === 3 && $teamKey > 0) {
|
||
$sqlTeamBib = "
|
||
SELECT no_bib
|
||
FROM resultats_participants
|
||
WHERE epr_id = $epr_id
|
||
AND pec_id = $teamKey
|
||
AND is_cancelled = 0
|
||
AND no_bib IS NOT NULL
|
||
AND no_bib <> ''
|
||
AND no_bib <> 0
|
||
AND par_id <> $par_id
|
||
LIMIT 1
|
||
";
|
||
$existingBib = (int)$objDatabase->fxGetVar($sqlTeamBib);
|
||
|
||
if ($existingBib > 0) {
|
||
$foundBib = $existingBib;
|
||
$teamNumber = $existingBib;
|
||
}
|
||
}
|
||
|
||
if ($foundBib === null) {
|
||
$findTeamMode = $isTeamEvent ? $teamMode : 1;
|
||
$foundBib = fxFindNextBatchBib($epr_id, $tabRanges, 'execute', $usedBib, $findTeamMode);
|
||
}
|
||
|
||
if ($foundBib === null) {
|
||
if (function_exists('fxcreer_log')) {
|
||
fxcreer_log('MSIN-4379: aucun dossard libre (epr_id=' . $epr_id . ', par_id=' . $par_id . ')');
|
||
}
|
||
|
||
if ($p && function_exists('fxEvtErreurOuvrir')) {
|
||
fxEvtErreurOuvrir('bib_auto_miss', [
|
||
'eve_id' => (int)($p['eve_id'] ?? 0),
|
||
'epr_id' => $epr_id,
|
||
'par_id' => $par_id,
|
||
'pec_id' => (int)($p['pec_id'] ?? 0),
|
||
'no_commande' => trim((string)($p['no_commande'] ?? '')),
|
||
'no_panier' => trim((string)($p['no_panier'] ?? '')),
|
||
'com_id' => (int)($p['com_id'] ?? 0),
|
||
]);
|
||
}
|
||
|
||
return ['success' => false, 'message' => 'aucun dossard disponible'];
|
||
}
|
||
|
||
fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib);
|
||
|
||
if ($isTeamEvent && $teamKey > 0) {
|
||
$updatedTeams = [];
|
||
|
||
if ($teamMode === 3) {
|
||
fxApplyBatchTeamNumber($epr_id, $teamKey, $foundBib, $updatedTeams);
|
||
} else {
|
||
$sqlEquipe = "
|
||
SELECT no_equipe
|
||
FROM resultats_epreuves_commandees
|
||
WHERE pec_id_original = $teamKey
|
||
AND epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
$teamNumber = (int)$objDatabase->fxGetVar($sqlEquipe);
|
||
|
||
if ($teamNumber <= 0) {
|
||
$sqlMaxTeam = "
|
||
SELECT MAX(CAST(no_equipe AS UNSIGNED))
|
||
FROM resultats_epreuves_commandees
|
||
WHERE epr_id = $epr_id
|
||
";
|
||
$teamNumber = (int)$objDatabase->fxGetVar($sqlMaxTeam) + 1;
|
||
}
|
||
|
||
fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams);
|
||
}
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'no_bib' => (int)$foundBib,
|
||
];
|
||
}
|
||
|
||
function fxInfosBibEpreuve($epr_id){
|
||
global $objDatabase;
|
||
|
||
static $memCache = [];
|
||
|
||
$epr_id = intval($epr_id);
|
||
|
||
if ($epr_id <= 0) {
|
||
return [
|
||
'total' => 0,
|
||
'avec_bib' => 0,
|
||
'sans_bib' => 0
|
||
];
|
||
}
|
||
|
||
if (isset($memCache[$epr_id])) {
|
||
return $memCache[$epr_id];
|
||
}
|
||
|
||
$sqlEpreuve = "
|
||
SELECT epr_equipe, epr_bib_team_mode
|
||
FROM inscriptions_epreuves
|
||
WHERE epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
$tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve);
|
||
$blnTeamOneBib = $tabEpreuve
|
||
&& (int)$tabEpreuve['epr_equipe'] === 1
|
||
&& (int)($tabEpreuve['epr_bib_team_mode'] ?? 1) === 3;
|
||
|
||
if ($blnTeamOneBib) {
|
||
// MSIN-4432 — aligné sur fxGetQuantites / fxCountBatchAssignUnits : une équipe = une unité.
|
||
$sql = "
|
||
SELECT
|
||
COUNT(DISTINCT p.pec_id) AS total,
|
||
COUNT(DISTINCT CASE
|
||
WHEN p.no_bib IS NOT NULL AND p.no_bib > 0 THEN p.pec_id
|
||
ELSE NULL
|
||
END) AS avec_bib
|
||
FROM resultats_participants p
|
||
WHERE p.epr_id = $epr_id
|
||
AND p.is_cancelled = 0
|
||
AND p.pec_id > 0
|
||
";
|
||
$row = $objDatabase->fxGetRow($sql);
|
||
$intTotal = (int)($row['total'] ?? 0);
|
||
$intAvecBib = (int)($row['avec_bib'] ?? 0);
|
||
} else {
|
||
$sql = "
|
||
SELECT
|
||
COUNT(*) AS total,
|
||
SUM(CASE WHEN no_bib IS NOT NULL AND no_bib > 0 THEN 1 ELSE 0 END) AS avec_bib
|
||
FROM resultats_participants
|
||
WHERE epr_id = $epr_id
|
||
AND is_cancelled = 0
|
||
";
|
||
$row = $objDatabase->fxGetRow($sql);
|
||
$intTotal = (int)($row['total'] ?? 0);
|
||
$intAvecBib = (int)($row['avec_bib'] ?? 0);
|
||
}
|
||
|
||
$info = [
|
||
'total' => $intTotal,
|
||
'avec_bib' => $intAvecBib,
|
||
'sans_bib' => max(0, $intTotal - $intAvecBib),
|
||
'a_assigner' => fxCountBatchAssignUnits($epr_id)
|
||
];
|
||
|
||
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;
|
||
|
||
$sqlUpdate = "
|
||
UPDATE resultats_participants
|
||
SET no_bib = " . intval($foundBib) . ",
|
||
par_date_bib = IFNULL(par_date_bib, NOW())
|
||
WHERE par_id = " . intval($par_id) . "
|
||
AND is_cancelled = 0
|
||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||
";
|
||
|
||
$objDatabase->fxQuery($sqlUpdate);
|
||
$intAffected = (int)$objDatabase->affected_rows;
|
||
|
||
if ($intAffected > 0 && function_exists('fxEvtErreurResoudre')) {
|
||
fxEvtErreurResoudre('bib_auto_miss', (int)$epr_id, (int)$par_id);
|
||
}
|
||
|
||
return $intAffected;
|
||
}
|
||
|
||
function fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, &$updatedTeams) {
|
||
global $objDatabase;
|
||
|
||
if ($teamKey <= 0 || $teamNumber <= 0 || isset($updatedTeams[$teamKey])) {
|
||
return;
|
||
}
|
||
|
||
$sqlTeam = "
|
||
UPDATE resultats_epreuves_commandees
|
||
SET no_equipe = " . intval($teamNumber) . "
|
||
WHERE pec_id_original = " . intval($teamKey) . "
|
||
AND epr_id = " . intval($epr_id) . "
|
||
";
|
||
|
||
$objDatabase->fxQuery($sqlTeam);
|
||
$updatedTeams[$teamKey] = true;
|
||
}
|
||
|
||
function fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber) {
|
||
return [
|
||
'rol_id' => $p['rol_id'],
|
||
'par_id' => (int)$p['par_id'],
|
||
'par_prenom' => $p['par_prenom'],
|
||
'par_nom' => $p['par_nom'],
|
||
'no_bib' => $foundBib,
|
||
'no_equipe' => $teamNumber,
|
||
'pec_nom_equipe' => $p['pec_nom_equipe'] ?? '',
|
||
];
|
||
}
|
||
|
||
function fxGetBatchTeamKey($p) {
|
||
return (int)($p['pec_id_original'] ?? $p['pec_id'] ?? 0);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4433 — Mode équipe 3 : dossard déjà posé sur un coéquipier (batch par paquets).
|
||
*/
|
||
function fxGetExistingTeamBibInDb($epr_id, $teamKey) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = (int)$epr_id;
|
||
$teamKey = (int)$teamKey;
|
||
$sqlBibNum = fxBibSqlNoBibUnsigned('no_bib');
|
||
|
||
if ($epr_id <= 0 || $teamKey <= 0) {
|
||
return null;
|
||
}
|
||
|
||
$sql = "
|
||
SELECT $sqlBibNum
|
||
FROM resultats_participants
|
||
WHERE epr_id = $epr_id
|
||
AND pec_id = $teamKey
|
||
AND is_cancelled = 0
|
||
AND $sqlBibNum > 0
|
||
LIMIT 1
|
||
";
|
||
|
||
$bib = (int)$objDatabase->fxGetVar($sql);
|
||
|
||
return $bib > 0 ? $bib : null;
|
||
}
|
||
|
||
function fxCountBatchAssignUnits($epr_id, $participants = null) {
|
||
global $objDatabase;
|
||
|
||
$epr_id = intval($epr_id);
|
||
|
||
if ($epr_id <= 0) {
|
||
return 0;
|
||
}
|
||
|
||
$sqlEpreuve = "
|
||
SELECT epr_equipe, epr_bib_team_mode
|
||
FROM inscriptions_epreuves
|
||
WHERE epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
$tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve);
|
||
|
||
$countParticipants = function ($rows) {
|
||
return is_array($rows) ? count($rows) : 0;
|
||
};
|
||
|
||
if (!$tabEpreuve || (int)$tabEpreuve['epr_equipe'] !== 1) {
|
||
if (is_array($participants)) {
|
||
return $countParticipants($participants);
|
||
}
|
||
|
||
return (int)$objDatabase->fxGetVar("
|
||
SELECT COUNT(*)
|
||
FROM resultats_participants
|
||
WHERE epr_id = $epr_id
|
||
AND is_cancelled = 0
|
||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||
AND rol_id NOT IN (3, 4)
|
||
");
|
||
}
|
||
|
||
$teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1);
|
||
if ($teamMode <= 0) {
|
||
$teamMode = 1;
|
||
}
|
||
|
||
if ($teamMode !== 3) {
|
||
if (is_array($participants)) {
|
||
return $countParticipants($participants);
|
||
}
|
||
|
||
return (int)$objDatabase->fxGetVar("
|
||
SELECT COUNT(*)
|
||
FROM resultats_participants
|
||
WHERE epr_id = $epr_id
|
||
AND is_cancelled = 0
|
||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||
AND rol_id NOT IN (3, 4)
|
||
");
|
||
}
|
||
|
||
if (is_array($participants)) {
|
||
$teams = [];
|
||
|
||
foreach ($participants as $p) {
|
||
$teamKey = fxGetBatchTeamKey($p);
|
||
|
||
if ($teamKey > 0) {
|
||
$teams[$teamKey] = true;
|
||
}
|
||
}
|
||
|
||
return count($teams);
|
||
}
|
||
|
||
return (int)$objDatabase->fxGetVar("
|
||
SELECT COUNT(DISTINCT p.pec_id)
|
||
FROM resultats_participants p
|
||
WHERE p.epr_id = $epr_id
|
||
AND p.is_cancelled = 0
|
||
AND (p.no_bib IS NULL OR p.no_bib = '' OR p.no_bib = 0)
|
||
AND p.rol_id NOT IN (3, 4)
|
||
AND p.pec_id > 0
|
||
");
|
||
}
|
||
|
||
function fxProcessBatchAssignmentsSolo($epr_id, $participants, $tabRanges, $mode = 'simulation') {
|
||
$assignments = [];
|
||
// MSIN-4433 — état réel rechargé à chaque paquet (execute) ou simulation.
|
||
$usedBib = fxLoadUsedBibsForBatch($epr_id);
|
||
|
||
foreach ($participants as $p) {
|
||
$foundBib = fxTryAssignNextBibForParticipant(
|
||
$epr_id,
|
||
(int)$p['par_id'],
|
||
$tabRanges,
|
||
$mode,
|
||
$usedBib,
|
||
1
|
||
);
|
||
|
||
if ($foundBib === null) {
|
||
break;
|
||
}
|
||
|
||
$assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, 0);
|
||
}
|
||
|
||
return $assignments;
|
||
}
|
||
|
||
function fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mode, $teamMode) {
|
||
$assignments = [];
|
||
$teamMap = [];
|
||
$updatedTeams = [];
|
||
$teamBibMap = [];
|
||
$nextTeamNumber = 1;
|
||
$usedBib = fxLoadUsedBibsForBatch($epr_id);
|
||
|
||
foreach ($participants as $p) {
|
||
$par_id = (int)$p['par_id'];
|
||
$teamKey = fxGetBatchTeamKey($p);
|
||
$teamNumber = 0;
|
||
$foundBib = null;
|
||
|
||
if ($teamMode === 3 && $teamKey > 0) {
|
||
if (isset($teamBibMap[$teamKey])) {
|
||
$foundBib = $teamBibMap[$teamKey];
|
||
} else {
|
||
$foundBib = fxGetExistingTeamBibInDb($epr_id, $teamKey);
|
||
if ($foundBib !== null) {
|
||
$teamBibMap[$teamKey] = $foundBib;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($teamMode === 3 && $teamKey > 0 && $foundBib !== null) {
|
||
$teamNumber = $foundBib;
|
||
|
||
if ($mode === 'execute') {
|
||
$intAffected = fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib);
|
||
|
||
if ($intAffected <= 0) {
|
||
continue;
|
||
}
|
||
|
||
fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams);
|
||
}
|
||
} else {
|
||
if ($teamMode !== 3 && $teamKey > 0) {
|
||
if (!isset($teamMap[$teamKey])) {
|
||
$teamMap[$teamKey] = $nextTeamNumber;
|
||
$nextTeamNumber++;
|
||
}
|
||
|
||
$teamNumber = $teamMap[$teamKey];
|
||
}
|
||
|
||
$foundBib = fxTryAssignNextBibForParticipant(
|
||
$epr_id,
|
||
$par_id,
|
||
$tabRanges,
|
||
$mode,
|
||
$usedBib,
|
||
$teamMode
|
||
);
|
||
|
||
if ($foundBib === null) {
|
||
break;
|
||
}
|
||
|
||
if ($teamMode === 3 && $teamKey > 0) {
|
||
$teamBibMap[$teamKey] = $foundBib;
|
||
$teamNumber = $foundBib;
|
||
}
|
||
|
||
if ($mode === 'execute') {
|
||
fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams);
|
||
}
|
||
}
|
||
|
||
$assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber);
|
||
}
|
||
|
||
return $assignments;
|
||
}
|
||
|
||
function fxProcessBatchAssignments($epr_id, $participants, $tabRanges, $mode = 'simulation') {
|
||
global $objDatabase;
|
||
|
||
if (empty($participants) || empty($tabRanges)) {
|
||
return [];
|
||
}
|
||
|
||
$epr_id = intval($epr_id);
|
||
$sqlEpreuve = "
|
||
SELECT epr_equipe, epr_bib_team_mode
|
||
FROM inscriptions_epreuves
|
||
WHERE epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
$tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve);
|
||
|
||
// Épreuves solo : logique simple, inchangée (1 personne = 1 dossard)
|
||
if (!$tabEpreuve || (int)$tabEpreuve['epr_equipe'] !== 1) {
|
||
return fxProcessBatchAssignmentsSolo($epr_id, $participants, $tabRanges, $mode);
|
||
}
|
||
|
||
// Épreuves équipe uniquement — voir fxProcessBatchAssignmentsEquipe()
|
||
$teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1);
|
||
if ($teamMode <= 0) {
|
||
$teamMode = 1;
|
||
}
|
||
|
||
return fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mode, $teamMode);
|
||
}
|
||
|
||
/** MSIN-4433 — Clé session pour accumuler les lignes assignées entre paquets AJAX. */
|
||
function fxBibBatchExecSessionKey($epr_id) {
|
||
return 'bib_batch_exec_' . (int)$epr_id;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4433 — HTML résultat GO batch (batch_apply et dernier paquet).
|
||
*/
|
||
function fxBibBuildBatchApplyHtml($epr_id, array $exec, $intTotalInitial, $strLangue) {
|
||
$assigned = count($exec);
|
||
$total = max($assigned, (int)$intTotalInitial);
|
||
$remaining = max(0, $total - $assigned);
|
||
$status = 'success';
|
||
|
||
if ($assigned === 0) {
|
||
$status = 'error';
|
||
} elseif ($assigned < $total) {
|
||
$status = 'partial';
|
||
}
|
||
|
||
if ($assigned === 0) {
|
||
$info = fxBibMsg('bib_v4_ajax_assign_none');
|
||
} elseif ($assigned >= $total) {
|
||
$info = fxBibMsg('bib_v4_ajax_assign_full', $assigned);
|
||
} else {
|
||
$info = fxBibMsg('bib_v4_ajax_assign_partial', $assigned, $remaining);
|
||
}
|
||
|
||
return renderBibView(
|
||
$epr_id,
|
||
0,
|
||
$strLangue,
|
||
'execute',
|
||
$exec,
|
||
fxBibTexte('bib_v4_ajax_title_assign'),
|
||
$info,
|
||
$status
|
||
);
|
||
}
|
||
|
||
function fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id = 0) {
|
||
|
||
$nbParticipants = fxCountBatchAssignUnits($epr_id, $participants);
|
||
$nbDispo = 0;
|
||
|
||
if (!empty($tabRangesInfos)) {
|
||
foreach ($tabRangesInfos as $r) {
|
||
|
||
$total = (int)($r['nb_total_range'] ?? 0);
|
||
$used = (int)($r['nb_utilises'] ?? 0);
|
||
|
||
$nbDispo += max(0, $total - $used);
|
||
}
|
||
}
|
||
|
||
$nbAssignable = min($nbParticipants, $nbDispo);
|
||
$nbManque = max(0, $nbParticipants - $nbDispo);
|
||
|
||
return [
|
||
'nb_dispo' => $nbDispo,
|
||
'nb_participants' => $nbParticipants,
|
||
'nb_assignable' => $nbAssignable,
|
||
'nb_manque' => $nbManque
|
||
];
|
||
}
|
||
/**
|
||
* 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);
|
||
$fltW = $fltMaxW;
|
||
if (is_array($tabSize) && !empty($tabSize[0]) && !empty($tabSize[1])) {
|
||
$fltNatW = ($tabSize[0] * 25.4) / 96;
|
||
if ($fltNatW > 0 && $fltNatW < $fltMaxW) {
|
||
$fltW = $fltNatW;
|
||
}
|
||
}
|
||
$fltH = 0;
|
||
if (is_array($tabSize) && !empty($tabSize[0]) && !empty($tabSize[1])) {
|
||
$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);
|
||
$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 + logo pied de page.
|
||
$pdf->SetMargins(12, 40, 12);
|
||
$pdf->SetAutoPageBreak(true, 18);
|
||
|
||
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->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 — 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();
|
||
// Bandeau flyer (bleu MS1 + filet or).
|
||
$this->SetFillColor(47, 95, 208);
|
||
$this->Rect(0, 0, $fltW, 32, 'F');
|
||
$this->SetFillColor(255, 193, 7);
|
||
$this->Rect(0, 32, $fltW, 2, 'F');
|
||
|
||
$fltTextX = 12;
|
||
$strLogo = function_exists('fxBibDistPrintMs1LogoPath') ? fxBibDistPrintMs1LogoPath() : '';
|
||
if ($strLogo !== '') {
|
||
$fltLogoW = 34;
|
||
$this->Image($strLogo, 10, 9, $fltLogoW);
|
||
$fltTextX = 10 + $fltLogoW + 5;
|
||
}
|
||
|
||
$this->SetTextColor(255, 255, 255);
|
||
$this->SetXY($fltTextX, 6);
|
||
$this->SetFont('Arial', 'B', 14);
|
||
$this->Cell($fltW - $fltTextX - 10, 7, fxBibDistPrintPdfText($this->eventTitle), 0, 2, 'L');
|
||
$this->SetFont('Arial', 'B', 12);
|
||
$this->Cell($fltW - $fltTextX - 10, 6, fxBibDistPrintPdfText($this->documentTitle), 0, 2, 'L');
|
||
if (trim((string)$this->documentSubtitle) !== '') {
|
||
$this->SetFont('Arial', 'I', 9);
|
||
$this->SetTextColor(220, 230, 255);
|
||
$this->Cell($fltW - $fltTextX - 10, 5, fxBibDistPrintPdfText($this->documentSubtitle), 0, 2, 'L');
|
||
}
|
||
$this->SetTextColor(0, 0, 0);
|
||
$this->SetY(38);
|
||
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;
|
||
|
||
$fltLogoX = $fltPageW - $this->rMargin - $fltLogoW;
|
||
$fltLogoY = $fltPageH - 9.5;
|
||
$fltPageNumX = ($strLogo !== '')
|
||
? ($fltLogoX - $fltGap - $fltPageNumW)
|
||
: ($fltPageW - $this->rMargin - $fltPageNumW);
|
||
$fltTextW = max(30, $fltPageNumX - $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');
|
||
|
||
$strPage = sprintf($this->pageText, $this->PageNo(), '{nb}');
|
||
$this->SetXY($fltPageNumX, -11);
|
||
$this->Cell($fltPageNumW, 4, fxBibDistPrintPdfText($strPage), 0, 0, 'R');
|
||
$this->SetTextColor(0, 0, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
$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();
|
||
}
|