This commit introduces improvements to session management by implementing a new check for super admin sessions, allowing them to bypass certain access restrictions. It updates the logout function to retain super admin session data and modifies event access functions to grant permissions based on super admin status. Additionally, the session timeout duration is adjusted for better alignment with site requirements. The version code is updated to reflect these changes.
1635 lines
72 KiB
PHP
1635 lines
72 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Gestion des inscriptions — recherche, filtres, cartes, fiche.
|
|
*
|
|
* Deux entrees distinctes (meme module, navigation differente) :
|
|
* - Promoteur : /compte/inc_tableau_inscriptions_gestion → retour inc_tableau_promoteur
|
|
* - Acces v2 seul : /mobile → retour /mobile ou Mon compte
|
|
*
|
|
* Droits : v2 uniquement (fxInscrGestionCanAccess). i18n : toujours info_prg compte.php.
|
|
*/
|
|
|
|
function fxInscrGestionIsEntry() {
|
|
return defined('MS1_INSCR_GESTION_ENTRY') && MS1_INSCR_GESTION_ENTRY;
|
|
}
|
|
|
|
/** Utilisateur avec menu promoteur legacy (section Info promoteur). */
|
|
function fxInscrGestionUserHasPromoteurMenu($intComId) {
|
|
global $objDatabase;
|
|
|
|
$row = $objDatabase->fxGetRow(
|
|
'SELECT com_eve_promoteur, com_rapports FROM inscriptions_comptes WHERE com_id = ' . intval($intComId)
|
|
);
|
|
if ($row === null) {
|
|
return false;
|
|
}
|
|
|
|
return trim((string)$row['com_eve_promoteur']) !== '' || trim((string)$row['com_rapports']) !== '';
|
|
}
|
|
|
|
/** Permissions v2 requises pour la fiche de gestion des inscriptions (web). */
|
|
function fxInscrGestionPermKeysView() {
|
|
return array('registrations.view', 'inscriptions_gestion.view');
|
|
}
|
|
|
|
function fxInscrGestionPermKeysScan() {
|
|
return array('registrations.scan');
|
|
}
|
|
|
|
/** Permission action (niveau fonction dans la fiche de gestion). */
|
|
function fxInscrGestionCanDo($intComId, $intEveId, $strActionPerm) {
|
|
fxInscrGestionLoadEveAcces();
|
|
|
|
if (!fxInscrGestionCanAccess($intComId, $intEveId)) {
|
|
return false;
|
|
}
|
|
|
|
if (fxEveAccesHasPermission(intval($intComId), intval($intEveId), $strActionPerm)) {
|
|
return true;
|
|
}
|
|
|
|
/* Kit inscriptions complet (desktop) inclut les actions de gestion. */
|
|
if (fxEveAccesHasPermission(intval($intComId), intval($intEveId), 'inscriptions.edit')) {
|
|
return true;
|
|
}
|
|
|
|
/* dossards.manage autorise aussi la modification du no dossard sur la fiche de gestion. */
|
|
if ($strActionPerm === 'inscriptions_gestion.bib_edit'
|
|
&& fxEveAccesHasPermission(intval($intComId), intval($intEveId), 'dossards.manage')) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/** Badge cadenas (mode inspecteur super admin) sur la fiche de gestion. */
|
|
function fxInscrGestionPermInspectEcho($strPermKey) {
|
|
if (!function_exists('fxAdminPermInspectModeActive') || !fxAdminPermInspectModeActive()) {
|
|
return;
|
|
}
|
|
fxInscrGestionLoadEveAcces();
|
|
echo ' ' . fxEveAccesPermInspectBadge($strPermKey, 'inscr_gestion');
|
|
}
|
|
|
|
/** Badge + libelle pour un controle masque par les droits (mode inspecteur). */
|
|
function fxInscrGestionPermInspectEchoHidden($strPermKey, $strLabel) {
|
|
if (!function_exists('fxAdminPermInspectModeActive') || !fxAdminPermInspectModeActive()) {
|
|
return;
|
|
}
|
|
fxInscrGestionLoadEveAcces();
|
|
echo '<span class="ms1-perm-inspect-slot">';
|
|
echo fxEveAccesPermInspectBadge($strPermKey, 'inscr_gestion');
|
|
echo ' <span class="text-muted small">' . fxInscrGestionEsc($strLabel) . '</span>';
|
|
echo '</span> ';
|
|
}
|
|
|
|
function fxInscrGestionLoadEveAcces() {
|
|
require_once __DIR__ . '/inc_fx_eve_acces.php';
|
|
}
|
|
|
|
/**
|
|
* Evenements accessibles via acces v2 uniquement (pas com_eve_promoteur, pas super admin).
|
|
*/
|
|
function fxInscrGestionGetPromoteurEveIds($intComId) {
|
|
fxInscrGestionLoadEveAcces();
|
|
return fxEveAccesGetEventIdsWithInscrGestionAccess(intval($intComId));
|
|
}
|
|
|
|
function fxInscrGestionCanAccess($intComId, $intEveId) {
|
|
if (!empty($_SESSION['usa_id'])) {
|
|
return true;
|
|
}
|
|
|
|
fxInscrGestionLoadEveAcces();
|
|
return fxEveAccesHasInscrGestionWebAccess(intval($intComId), intval($intEveId));
|
|
}
|
|
|
|
function fxInscrGestionCanScan($intComId, $intEveId) {
|
|
if (!empty($_SESSION['usa_id'])) {
|
|
return true;
|
|
}
|
|
|
|
fxInscrGestionLoadEveAcces();
|
|
return fxEveAccesHasAnyPermission(intval($intComId), intval($intEveId), fxInscrGestionPermKeysScan());
|
|
}
|
|
|
|
function fxInscrGestionBaseUrl($strLangue, $blnMobileEntry = null) {
|
|
global $vDomaine;
|
|
|
|
if ($blnMobileEntry === null) {
|
|
$blnMobileEntry = fxInscrGestionIsEntry();
|
|
}
|
|
if ($blnMobileEntry) {
|
|
return $vDomaine . '/mobile';
|
|
}
|
|
|
|
return $vDomaine . ($strLangue === 'fr' ? '/compte/inc_tableau_inscriptions_gestion' : '/account/inc_tableau_inscriptions_gestion');
|
|
}
|
|
|
|
function fxInscrGestionEsc($str) {
|
|
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
/** Page info / i18n des libelles de gestion des inscriptions (toujours compte.php). */
|
|
function fxInscrGestionTextesPage() {
|
|
return 'compte.php';
|
|
}
|
|
|
|
function fxInscrGestionLoadTextes($strLangue) {
|
|
static $tabCache = array();
|
|
static $strCacheLang = '';
|
|
|
|
if ($strCacheLang === $strLangue && !empty($tabCache)) {
|
|
return $tabCache;
|
|
}
|
|
|
|
$tabCache = obtenirTextepage(fxInscrGestionTextesPage(), $strLangue, 2);
|
|
if (!is_array($tabCache)) {
|
|
$tabCache = array();
|
|
}
|
|
$strCacheLang = $strLangue;
|
|
|
|
return $tabCache;
|
|
}
|
|
|
|
/**
|
|
* Recherche un libelle info par clef (toutes pages), priorite compte.php > global > mobile.php.
|
|
*/
|
|
function fxInscrGestionLookupTexteDb($strClef, $strLangue) {
|
|
global $objDatabase;
|
|
|
|
static $tabMemo = array();
|
|
$strMemoKey = $strClef . "\0" . $strLangue;
|
|
|
|
if (array_key_exists($strMemoKey, $tabMemo)) {
|
|
return $tabMemo[$strMemoKey];
|
|
}
|
|
|
|
$sql = "SELECT info_texte FROM info
|
|
WHERE info_clef = '" . $objDatabase->fxEscape($strClef) . "'
|
|
AND info_langue = '" . $objDatabase->fxEscape($strLangue) . "'
|
|
AND info_actif = 1
|
|
ORDER BY FIELD(info_prg, 'compte.php', 'global', 'mobile.php', 'mobile')
|
|
LIMIT 1";
|
|
$strTexte = $objDatabase->fxGetVar($sql);
|
|
|
|
if ($strTexte === null || trim((string)$strTexte) === '' || trim((string)$strTexte) === $strClef) {
|
|
$tabMemo[$strMemoKey] = null;
|
|
return null;
|
|
}
|
|
|
|
$tabMemo[$strMemoKey] = (string)$strTexte;
|
|
return $tabMemo[$strMemoKey];
|
|
}
|
|
|
|
function fxInscrGestionResolveTexte($strClef, $strLangue) {
|
|
global $vtexte_page;
|
|
|
|
$tab = fxInscrGestionLoadTextes($strLangue);
|
|
|
|
if (isset($tab[$strClef]['info_texte'])) {
|
|
$str = trim((string)$tab[$strClef]['info_texte']);
|
|
if ($str !== '' && $str !== $strClef) {
|
|
return $str;
|
|
}
|
|
}
|
|
|
|
if (is_array($vtexte_page) && isset($vtexte_page[$strClef]['info_texte'])) {
|
|
$str = trim((string)$vtexte_page[$strClef]['info_texte']);
|
|
if ($str !== '' && $str !== $strClef) {
|
|
return $str;
|
|
}
|
|
}
|
|
|
|
$strDb = fxInscrGestionLookupTexteDb($strClef, $strLangue);
|
|
if ($strDb !== null) {
|
|
return $strDb;
|
|
}
|
|
|
|
if (function_exists('fxAdminCanUseTextEditTools') && fxAdminCanUseTextEditTools()) {
|
|
global $vPage;
|
|
$memPage = $vPage;
|
|
$vPage = fxInscrGestionTextesPage();
|
|
$str = afficheTexte($strClef, 0);
|
|
$vPage = $memPage;
|
|
if (strpos($str, '*') === 0 && substr($str, -1) === '*') {
|
|
return fxInscrGestionFallbackTexte($strClef, $strLangue);
|
|
}
|
|
if (trim($str) === '' || trim($str) === $strClef) {
|
|
return fxInscrGestionFallbackTexte($strClef, $strLangue);
|
|
}
|
|
return $str;
|
|
}
|
|
|
|
return fxInscrGestionFallbackTexte($strClef, $strLangue);
|
|
}
|
|
|
|
/** Libelles integres (secours si table info non a jour). */
|
|
function fxInscrGestionFallbackTexte($strClef, $strLangue) {
|
|
static $tabMemo = array();
|
|
|
|
if (!isset($tabMemo[$strLangue])) {
|
|
$blnFr = ($strLangue !== 'en');
|
|
$tabMemo[$strLangue] = array(
|
|
'inscr_gestion_qr_title' => $blnFr ? 'Code QR — Lecteur' : 'QR code reader',
|
|
'inscr_gestion_qr_hint' => $blnFr ? 'Pointez la caméra vers le code QR du participant.' : 'Point the camera at the participant\'s QR code.',
|
|
'inscr_gestion_qr_invalid' => $blnFr ? 'Code QR invalide ou introuvable.' : 'Invalid or unknown QR code.',
|
|
'inscr_gestion_qr_not_found' => $blnFr ? 'Participant introuvable pour cet événement.' : 'Participant not found for this event.',
|
|
'inscr_gestion_qr_wrong_event' => $blnFr ? 'Ce code QR appartient à un autre événement : %s' : 'This QR code belongs to another event: %s',
|
|
'inscr_gestion_qr_camera_error' => $blnFr ? 'Impossible d\'accéder à la caméra.' : 'Unable to access the camera.',
|
|
'inscr_gestion_bib_scan_btn' => $blnFr ? 'Scanner le numéro' : 'Scan number',
|
|
'inscr_gestion_bib_scan_hint' => $blnFr ? 'Ouvrez la caméra, cadrez le numéro, puis touchez l\'image pour lire.' : 'Open the camera, frame the number, then tap the image to read.',
|
|
'inscr_gestion_bib_scan_ready' => $blnFr ? 'Cadrez le numéro, puis touchez l\'image' : 'Frame the number, then tap the image',
|
|
'inscr_gestion_bib_scan_tap' => $blnFr
|
|
? 'Centrez les numéros que vous voulez considérer comme numéro de dossard avant de cliquer.'
|
|
: 'Center the numbers you want to use as the bib number before tapping.',
|
|
'inscr_gestion_bib_scan_scanning' => $blnFr ? 'Lecture en cours...' : 'Reading...',
|
|
'inscr_gestion_bib_scan_loading' => $blnFr ? 'Initialisation (1re fois)...' : 'Initializing (first time)...',
|
|
'inscr_gestion_bib_scan_found' => $blnFr ? 'Numéro %s détecté — validez avec OK.' : 'Number %s detected — press OK.',
|
|
'inscr_gestion_bib_scan_invalid' => $blnFr ? 'Numéro illisible. Cadrez un seul numéro.' : 'Unreadable number. Frame a single number.',
|
|
// Libelles de la barre de boutons (fiche de gestion) — editables via la table info (page compte.php).
|
|
'inscr_gestion_show_invoice' => $blnFr ? 'Afficher la facture' : 'Show invoice',
|
|
'inscr_gestion_show_transaction' => $blnFr ? 'Afficher la transaction' : 'Show transaction',
|
|
'inscr_gestion_hide_transaction' => $blnFr ? 'Masquer la transaction' : 'Hide transaction',
|
|
'inscr_gestion_renvoi' => $blnFr ? 'Retourner confirmation' : 'Resend confirmation',
|
|
'inscr_gestion_modifier_participant' => $blnFr ? 'Modifier l\'inscription' : 'Edit registration',
|
|
// Invite affichee quand la page arrive vide (aucune recherche lancee).
|
|
'inscr_gestion_search_prompt' => $blnFr
|
|
? 'Utilisez la recherche ci-dessus pour afficher les inscriptions. Laissez les champs vides et lancez la recherche pour toutes les afficher.'
|
|
: 'Use the search above to display registrations. Leave the fields empty and search to show them all.',
|
|
// MSIN-4405 — Detail du statut annule (transfere / modifie / vraie annulation), derive en lecture.
|
|
'inscr_gestion_annulation_titre' => $blnFr ? 'Statut de l\'inscription' : 'Registration status',
|
|
'inscr_gestion_statut_annule' => $blnFr ? 'Annulée' : 'Cancelled',
|
|
'inscr_gestion_statut_transfert' => $blnFr ? 'Transférée' : 'Transferred',
|
|
'inscr_gestion_statut_modif' => $blnFr ? 'Modifiée (changement d\'épreuve)' : 'Modified (race change)',
|
|
);
|
|
}
|
|
|
|
if (isset($tabMemo[$strLangue][$strClef])) {
|
|
return $tabMemo[$strLangue][$strClef];
|
|
}
|
|
|
|
return $strClef;
|
|
}
|
|
|
|
/** Charge $vtexte_page pour le module gestion (entry /mobile ou compte). */
|
|
function fxInscrGestionInitTextes($strLangue) {
|
|
global $vtexte_page, $vPage;
|
|
|
|
$vPage = fxInscrGestionTextesPage();
|
|
$vtexte_page = fxInscrGestionLoadTextes($strLangue);
|
|
}
|
|
|
|
/** Libelle i18n sans echo parasite — independant de la page PHP courante. */
|
|
function fxInscrGestionT($strClef) {
|
|
global $strLangue;
|
|
|
|
if (!isset($strLangue) || $strLangue === '') {
|
|
$strLangue = 'fr';
|
|
}
|
|
|
|
$strTexte = fxInscrGestionResolveTexte($strClef, $strLangue);
|
|
|
|
if ($strTexte === $strClef || trim((string)$strTexte) === '') {
|
|
$strFallback = fxInscrGestionFallbackTexte($strClef, $strLangue);
|
|
if ($strFallback !== $strClef && trim((string)$strFallback) !== '') {
|
|
$strTexte = $strFallback;
|
|
}
|
|
}
|
|
|
|
if (function_exists('fxAdminTradMarker')) {
|
|
$strMarker = fxAdminTradMarker($strClef, 0);
|
|
if ($strMarker !== '' && strpos($strTexte, $strMarker) === false) {
|
|
$strTexte .= $strMarker;
|
|
}
|
|
}
|
|
|
|
return $strTexte;
|
|
}
|
|
|
|
/**
|
|
* Libelle "robuste" pour les pastilles du scanner : si la table info renvoie une
|
|
* clef i18n brute (donnee corrompue, ex. ancien 'inscr_mobile_bib_scan_tap' jamais
|
|
* traduit), on l'ignore et on prend le libelle integre. Evite d'afficher une clef
|
|
* technique a l'usager. Pas de marqueur d'edition ici (texte affiche dans la video).
|
|
*/
|
|
function fxInscrGestionScanLabel($strClef) {
|
|
global $strLangue;
|
|
|
|
$strLang = (isset($strLangue) && $strLangue !== '') ? $strLangue : 'fr';
|
|
$strTexte = trim((string)fxInscrGestionResolveTexte($strClef, $strLang));
|
|
|
|
if ($strTexte === '' || preg_match('/^[a-z][a-z0-9]*(_[a-z0-9]+)+$/', $strTexte)) {
|
|
$strTexte = fxInscrGestionFallbackTexte($strClef, $strLang);
|
|
}
|
|
|
|
return $strTexte;
|
|
}
|
|
|
|
function fxInscrGestionLoginActionUrl($strLangue) {
|
|
global $vDomaine;
|
|
|
|
if ($strLangue === 'en') {
|
|
return $vDomaine . '/mobile/en';
|
|
}
|
|
|
|
return $vDomaine . '/mobile';
|
|
}
|
|
|
|
function fxInscrGestionRenderLoginPage($strLangue) {
|
|
$strActionUrl = fxInscrGestionLoginActionUrl($strLangue);
|
|
$strLblUser = ($strLangue === 'fr') ? 'Nom d\'utilisateur' : 'Username';
|
|
$strLblPass = ($strLangue === 'fr') ? 'Mot de passe' : 'Password';
|
|
$strBtn = ($strLangue === 'fr') ? 'Connexion' : 'Sign in';
|
|
$strIntro = ($strLangue === 'fr')
|
|
? 'Connectez-vous pour accéder aux inscriptions mobile.'
|
|
: 'Sign in to access mobile registrations.';
|
|
|
|
echo '<div class="inscr-gestion-page inscr-gestion-login-wrap">';
|
|
echo '<div id="module-inscr-gestion" class="inscr-gestion-shell inscr-gestion-shell--login">';
|
|
fxInscrGestionRenderPageHead(
|
|
($strLangue === 'fr') ? 'Inscriptions mobile' : 'Mobile registrations'
|
|
);
|
|
echo '<p class="inscr-gestion-login-intro text-muted">' . fxInscrGestionEsc($strIntro) . '</p>';
|
|
echo '<form action="' . fxInscrGestionEsc($strActionUrl) . '" id="frm_inscr_gestion_login" method="post" class="inscr-gestion-login-form">';
|
|
echo '<input type="hidden" name="form_action" value="' . fxInscrGestionEsc(urlencode(base64_encode('login'))) . '">';
|
|
echo '<label class="inscr-gestion-label" for="txt_login_mobile">' . fxInscrGestionEsc($strLblUser) . '</label>';
|
|
echo '<input class="form-control form-control-sm rounded-0" type="text" id="txt_login_mobile" name="txt_login" required autofocus>';
|
|
echo '<label class="inscr-gestion-label" for="txt_password_mobile">' . fxInscrGestionEsc($strLblPass) . '</label>';
|
|
echo '<input class="form-control form-control-sm rounded-0" type="password" id="txt_password_mobile" name="txt_password" required>';
|
|
echo '<button class="btn btn-primary btn-sm rounded-0 btn-block mt-3" type="submit" id="btn_login_mobile" name="btn_login">' . fxInscrGestionEsc($strBtn) . '</button>';
|
|
echo '</form></div></div>';
|
|
}
|
|
|
|
/** Libellé menu promoteur V2 (même texte que l'ancien + suffixe V2). */
|
|
function fxInscrGestionPromoteurMenuLabel() {
|
|
return afficheTexte('tableau_promoteur_menueinscription', 0) . ' V2';
|
|
}
|
|
|
|
function fxInscrGestionListBackLabel($strLangue) {
|
|
if (fxInscrGestionIsEntry()) {
|
|
return ($strLangue === 'fr') ? 'Événements' : 'Events';
|
|
}
|
|
|
|
return fxInscrGestionT('promoteur_back');
|
|
}
|
|
|
|
function fxInscrGestionShouldShowListBack($intComId) {
|
|
if (!fxInscrGestionIsEntry()) {
|
|
return true;
|
|
}
|
|
|
|
return count(fxInscrGestionGetPromoteurEveIds($intComId)) > 1;
|
|
}
|
|
|
|
function fxInscrGestionRenderNavBack($strUrl, $strLabel) {
|
|
echo '<a class="btn btn-primary rounded-pill inscr-gestion-nav-back" href="' . fxInscrGestionEsc($strUrl) . '">';
|
|
echo '<i class="fa fa-chevron-left mr-2" aria-hidden="true"></i>' . fxInscrGestionEsc($strLabel);
|
|
echo '</a>';
|
|
}
|
|
|
|
function fxInscrGestionRenderPageHead($strTitle, $strSub = '') {
|
|
echo '<div class="inscr-gestion-page-head">';
|
|
echo '<h1 class="inscr-gestion-page-title">' . fxInscrGestionEsc($strTitle) . '</h1>';
|
|
if (trim((string)$strSub) !== '') {
|
|
echo '<p class="inscr-gestion-page-sub text-muted mb-0">' . fxInscrGestionEsc($strSub) . '</p>';
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
function fxInscrGestionRenderSectionTitle($strLabel, $strIconClass) {
|
|
echo '<h2 class="inscr-gestion-fiche-section__title">';
|
|
echo '<i class="fa ' . fxInscrGestionEsc($strIconClass) . ' inscr-gestion-fiche-section__icon" aria-hidden="true"></i>';
|
|
echo '<span>' . fxInscrGestionEsc($strLabel) . '</span>';
|
|
echo '</h2>';
|
|
}
|
|
|
|
function fxInscrGestionRenderFicheSectionStart($strModifier, $strLabel, $strIconClass, $blnOpen = true) {
|
|
echo '<details class="inscr-gestion-fiche-section inscr-gestion-fiche-section--' . fxInscrGestionEsc($strModifier) . '"';
|
|
if ($blnOpen) {
|
|
echo ' open';
|
|
}
|
|
echo '>';
|
|
echo '<summary class="inscr-gestion-fiche-section__title">';
|
|
echo '<i class="fa ' . fxInscrGestionEsc($strIconClass) . ' inscr-gestion-fiche-section__icon" aria-hidden="true"></i>';
|
|
echo '<span>' . fxInscrGestionEsc($strLabel) . '</span>';
|
|
echo '</summary>';
|
|
echo '<div class="inscr-gestion-fiche-section__body">';
|
|
}
|
|
|
|
function fxInscrGestionRenderFicheSectionEnd() {
|
|
echo '</div></details>';
|
|
}
|
|
|
|
function fxInscrGestionRenderPanelSummary($strLabel, $strIconClass) {
|
|
echo '<i class="fa ' . fxInscrGestionEsc($strIconClass) . ' inscr-gestion-panel__icon" aria-hidden="true"></i>';
|
|
echo '<span>' . fxInscrGestionEsc($strLabel) . '</span>';
|
|
}
|
|
|
|
function fxInscrGestionParseEveId($strRaw) {
|
|
if ($strRaw === null || $strRaw === '') {
|
|
return 0;
|
|
}
|
|
$strDecoded = base64_decode(urldecode($strRaw), true);
|
|
if ($strDecoded === false || $strDecoded === '') {
|
|
return 0;
|
|
}
|
|
|
|
return (int)$strDecoded;
|
|
}
|
|
|
|
function fxInscrGestionParseRequest() {
|
|
$arr = array(
|
|
'rech_prenom' => isset($_GET['rech_prenom']) ? trim($_GET['rech_prenom']) : '',
|
|
'rech_nom' => isset($_GET['rech_nom']) ? trim($_GET['rech_nom']) : '',
|
|
'rech_no_commande' => isset($_GET['rech_no_commande']) ? trim($_GET['rech_no_commande']) : '',
|
|
'rech_nom_equipe' => isset($_GET['rech_nom_equipe']) ? trim($_GET['rech_nom_equipe']) : '',
|
|
'chk_bib' => !empty($_GET['chk_bib']) ? 1 : 0,
|
|
'chk_cancelled' => !empty($_GET['chk_cancelled']) ? 1 : 0,
|
|
'sel_rech_epreuve' => 0,
|
|
'pg' => isset($_GET['pg']) ? max(1, intval($_GET['pg'])) : 1,
|
|
'pec_id' => isset($_GET['pec_id']) ? intval($_GET['pec_id']) : 0,
|
|
// q = 1 lorsque l'utilisateur a lance une recherche/filtre. La liste reste vide tant que q = 0.
|
|
'q' => 0,
|
|
);
|
|
|
|
if (!empty($_GET['sel_rech_epreuve'])) {
|
|
$decoded = base64_decode(urldecode($_GET['sel_rech_epreuve']), true);
|
|
if ($decoded !== false && $decoded !== '') {
|
|
$arr['sel_rech_epreuve'] = intval($decoded);
|
|
} else {
|
|
$arr['sel_rech_epreuve'] = intval($_GET['sel_rech_epreuve']);
|
|
}
|
|
}
|
|
|
|
// Recherche "active" si : bouton Rechercher/Filtres soumis, marqueur q transporte par les liens,
|
|
// ou au moins un critere present (utile pour le retour depuis une fiche / la pagination).
|
|
$blnSubmit = !empty($_GET['btn_recherche']) || !empty($_GET['apply_filters']) || !empty($_GET['q']);
|
|
$blnCriteria = ($arr['rech_prenom'] !== '' || $arr['rech_nom'] !== '' || $arr['rech_no_commande'] !== ''
|
|
|| $arr['rech_nom_equipe'] !== '' || $arr['sel_rech_epreuve'] > 0 || $arr['chk_bib'] || $arr['chk_cancelled']);
|
|
$arr['q'] = ($blnSubmit || $blnCriteria) ? 1 : 0;
|
|
|
|
return $arr;
|
|
}
|
|
|
|
function fxInscrGestionFilterActiveCount($arrReq) {
|
|
$int = 0;
|
|
if ($arrReq['sel_rech_epreuve'] > 0) {
|
|
$int++;
|
|
}
|
|
if ($arrReq['chk_bib']) {
|
|
$int++;
|
|
}
|
|
if ($arrReq['chk_cancelled']) {
|
|
$int++;
|
|
}
|
|
return $int;
|
|
}
|
|
|
|
function fxInscrGestionEmptyListRequest() {
|
|
return array(
|
|
'rech_prenom' => '',
|
|
'rech_nom' => '',
|
|
'rech_no_commande' => '',
|
|
'rech_nom_equipe' => '',
|
|
'chk_bib' => 0,
|
|
'chk_cancelled' => 0,
|
|
'sel_rech_epreuve' => 0,
|
|
'pg' => 1,
|
|
'pec_id' => 0,
|
|
'q' => 0,
|
|
);
|
|
}
|
|
|
|
function fxInscrGestionSearchResetUrl($strBaseUrl, $intEveId) {
|
|
return fxInscrGestionBuildUrl($strBaseUrl, $intEveId, fxInscrGestionEmptyListRequest(), array('pg' => 1));
|
|
}
|
|
|
|
function fxInscrGestionBuildWhere($intEveId, $arrReq) {
|
|
global $objDatabase;
|
|
|
|
$strWhere = ' e.eve_id = ' . intval($intEveId);
|
|
|
|
if ($arrReq['rech_nom'] !== '') {
|
|
$strWhere .= ' AND p.par_nom LIKE "%' . $objDatabase->fxEscape($arrReq['rech_nom']) . '%"';
|
|
}
|
|
if ($arrReq['rech_prenom'] !== '') {
|
|
$strWhere .= ' AND p.par_prenom LIKE "%' . $objDatabase->fxEscape($arrReq['rech_prenom']) . '%"';
|
|
}
|
|
if ($arrReq['rech_no_commande'] !== '') {
|
|
$strEscCmd = $objDatabase->fxEscape($arrReq['rech_no_commande']);
|
|
$strWhere .= ' AND (e.no_commande LIKE "%' . $strEscCmd . '%" OR p.no_commande LIKE "%' . $strEscCmd . '%")';
|
|
}
|
|
if ($arrReq['rech_nom_equipe'] !== '') {
|
|
$strEscBibEquipe = $objDatabase->fxEscape($arrReq['rech_nom_equipe']);
|
|
$strWhere .= ' AND ('
|
|
. ' TRIM(p.no_bib) LIKE "%' . $strEscBibEquipe . '%"'
|
|
. ' OR TRIM(e.no_equipe) LIKE "%' . $strEscBibEquipe . '%"'
|
|
. ' OR e.pec_nom_equipe LIKE "%' . $strEscBibEquipe . '%"'
|
|
. ' OR p.par_nom_equipe LIKE "%' . $strEscBibEquipe . '%"'
|
|
. ')';
|
|
}
|
|
if ($arrReq['sel_rech_epreuve'] > 0) {
|
|
$strWhere .= ' AND p.epr_id = ' . intval($arrReq['sel_rech_epreuve']) . ' AND p.epr_id = e.epr_id';
|
|
}
|
|
if ($arrReq['chk_bib']) {
|
|
$strWhere .= " AND TRIM(p.no_bib) = ''";
|
|
}
|
|
if ($arrReq['chk_cancelled']) {
|
|
$strWhere .= ' AND e.is_cancelled = 1';
|
|
} else {
|
|
$strWhere .= ' AND e.is_cancelled = 0 AND e.pec_actif = 1';
|
|
}
|
|
|
|
return $strWhere;
|
|
}
|
|
|
|
function fxInscrGestionFetchRows($intEveId, $arrReq) {
|
|
global $objDatabase;
|
|
|
|
$strWhere = fxInscrGestionBuildWhere($intEveId, $arrReq);
|
|
$sql = 'SELECT p.no_bib, p.no_bib_remis, p.no_bib_remis_date, p.no_bib_remis_par, p.par_statut_course, 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'
|
|
. ' ORDER BY p.par_nom, p.par_prenom';
|
|
|
|
return $objDatabase->fxGetResults($sql);
|
|
}
|
|
|
|
function fxInscrGestionFetchRowByPec($intPecId, $intEveId) {
|
|
global $objDatabase;
|
|
|
|
$sql = 'SELECT p.no_bib, p.no_bib_remis, p.no_bib_remis_date, p.no_bib_remis_par, p.par_statut_course, 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 e.eve_id = ' . intval($intEveId)
|
|
. ' AND e.pec_id_original = ' . intval($intPecId)
|
|
. ' AND p.pec_id = e.pec_id_original'
|
|
. ' LIMIT 1';
|
|
|
|
return $objDatabase->fxGetRow($sql);
|
|
}
|
|
|
|
/**
|
|
* Politique de gestion des dossards en double pour un evenement.
|
|
* Pour l'instant : toujours 'warn' (avertissement non bloquant).
|
|
*
|
|
* Hook prevu pour le futur : lire un reglage par evenement afin de renvoyer
|
|
* 'block' (interdiction totale) ou 'allow' (doublons silencieux). Exemple :
|
|
* $rec = fxGetEvenementsId($intEveId);
|
|
* if (!empty($rec['eve_bib_doublon_interdit'])) return 'block';
|
|
* if (!empty($rec['eve_bib_doublon_autorise'])) return 'allow';
|
|
*
|
|
* @return string 'warn' | 'block' | 'allow'
|
|
*/
|
|
function fxInscrGestionBibDuplicatePolicy($intEveId) {
|
|
return 'warn';
|
|
}
|
|
|
|
/**
|
|
* Participants d'un evenement deja porteurs du dossard donne (hors la commande
|
|
* courante). Alimente le garde-fou "dossard en double".
|
|
*
|
|
* @param bool $blnTeam true = dossard d'equipe (e.no_equipe), false = individuel (p.no_bib)
|
|
* @return array liste de lignes ['par_nom','par_prenom','epr_id']
|
|
*/
|
|
function fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intExceptPec, $blnTeam) {
|
|
global $objDatabase;
|
|
|
|
$strNoBib = trim((string)$strNoBib);
|
|
if (intval($intEveId) <= 0 || $strNoBib === '') {
|
|
return array();
|
|
}
|
|
|
|
$strBibCol = $blnTeam ? 'e.no_equipe' : 'p.no_bib';
|
|
$sql = 'SELECT p.par_nom, p.par_prenom, e.epr_id'
|
|
. ' FROM resultats_epreuves_commandees e, resultats_participants p'
|
|
. ' WHERE e.eve_id = ' . intval($intEveId)
|
|
. ' AND p.pec_id = e.pec_id_original'
|
|
. ' AND e.is_cancelled = 0 AND e.pec_actif = 1'
|
|
. " AND TRIM(" . $strBibCol . ") = '" . $objDatabase->fxEscape($strNoBib) . "'"
|
|
. ' AND e.pec_id_original <> ' . intval($intExceptPec)
|
|
. ' GROUP BY e.pec_id_original'
|
|
. ' ORDER BY p.par_nom, p.par_prenom';
|
|
|
|
$tab = $objDatabase->fxGetResults($sql);
|
|
return is_array($tab) ? $tab : array();
|
|
}
|
|
|
|
function fxInscrGestionEpreuveLabel($intEprId, $strLangue) {
|
|
$tab = fxGetEpreuve($intEprId);
|
|
if ($tab === null) {
|
|
return '';
|
|
}
|
|
|
|
$str = '';
|
|
if (trim($tab['epr_categorie_' . $strLangue]) !== '') {
|
|
$str .= $tab['epr_categorie_' . $strLangue] . ' — ';
|
|
}
|
|
$str .= $tab['epr_type_' . $strLangue];
|
|
if (trim($tab['epr_nom_' . $strLangue]) !== '') {
|
|
$str .= ' — ' . $tab['epr_nom_' . $strLangue];
|
|
}
|
|
|
|
return fxUnescape($str);
|
|
}
|
|
|
|
function fxInscrGestionBibDisplay($arrRow) {
|
|
if (intval($arrRow['pec_equipe']) === 1) {
|
|
return fxShowBibNumber($arrRow['no_equipe'], $arrRow['epr_id'], 'equipe');
|
|
}
|
|
return fxShowBibNumber($arrRow['no_bib'], $arrRow['epr_id'], 'participant');
|
|
}
|
|
|
|
function fxInscrGestionRenderKvListOpen() {
|
|
echo '<div class="inscr-gestion-kv-list">';
|
|
}
|
|
|
|
function fxInscrGestionRenderKvListClose() {
|
|
echo '</div>';
|
|
}
|
|
|
|
function fxInscrGestionRenderKvRow($strLabel, $strValue, $blnHtml = false, $strExtraClass = '') {
|
|
if (!$blnHtml && trim((string)$strValue) === '') {
|
|
return;
|
|
}
|
|
|
|
$strClass = 'inscr-gestion-kv-row';
|
|
if ($strExtraClass !== '') {
|
|
$strClass .= ' ' . $strExtraClass;
|
|
}
|
|
|
|
echo '<div class="' . fxInscrGestionEsc($strClass) . '">';
|
|
echo '<div class="inscr-gestion-kv-row__label">' . fxInscrGestionEsc($strLabel) . '</div>';
|
|
echo '<div class="inscr-gestion-kv-row__value">';
|
|
if ($blnHtml) {
|
|
echo $strValue;
|
|
} else {
|
|
echo fxInscrGestionEsc($strValue);
|
|
}
|
|
echo '</div></div>';
|
|
}
|
|
|
|
function fxInscrGestionFetchFicheProfile($arrRow, $strLangue) {
|
|
global $objDatabase;
|
|
|
|
$intParId = (int)$arrRow['par_id'];
|
|
$intPecId = (int)$arrRow['pec_id_original'];
|
|
$intEveId = (int)$arrRow['eve_id'];
|
|
$strLangCol = ($strLangue === 'en') ? 'en' : 'fr';
|
|
|
|
// Le titre "Capitaine" n'a de sens qu'en epreuve d'equipe : meme condition que le champ "Type"
|
|
// de la fiche (cf. fxInscrGestionRenderFiche). En individuel, on ne l'affiche pas, meme si rol_id=1.
|
|
$blnEquipe = (intval($arrRow['pec_equipe']) === 1)
|
|
&& fxIsParEquipe((int)$arrRow['pec_id_original'], (int)$arrRow['epr_id']);
|
|
$blnCapitaine = ((int)$arrRow['rol_id'] === 1) && $blnEquipe;
|
|
|
|
$tabProfile = $objDatabase->fxGetRow(
|
|
'SELECT p.par_courriel, p.par_naissance, p.par_sexe, p.par_id_original'
|
|
. ' FROM resultats_participants p'
|
|
. ' WHERE p.par_id = ' . $intParId
|
|
. ' LIMIT 1'
|
|
);
|
|
|
|
if ($tabProfile === null) {
|
|
return array(
|
|
'bln_capitaine' => $blnCapitaine,
|
|
'email' => '',
|
|
'birth_gender' => '',
|
|
'questions' => array(),
|
|
);
|
|
}
|
|
|
|
$strEmail = trim((string)$tabProfile['par_courriel']);
|
|
|
|
$strBirthGender = '';
|
|
$strNaissance = trim((string)$tabProfile['par_naissance']);
|
|
if ($strNaissance !== '' && $strNaissance !== '0000-00-00') {
|
|
$strBirthGender = fxShowDate($strNaissance, $strLangue)
|
|
. ' - '
|
|
. fxGetGender($tabProfile['par_sexe'], $strLangue);
|
|
}
|
|
|
|
$intParIdOriginal = (int)$tabProfile['par_id_original'];
|
|
$sqlQuestions = 'SELECT rq.que_choix_' . $strLangCol . ' AS que_choix,'
|
|
. ' iq.que_cart_label_' . $strLangCol . ' AS que_label,'
|
|
. ' rq.que_question_' . $strLangCol . ' AS que_question,'
|
|
. ' iq.que_tri, iq.que_id'
|
|
. ' FROM resultats_questions rq'
|
|
. ' INNER JOIN inscriptions_questions iq ON iq.que_id = rq.que_id'
|
|
. ' WHERE iq.que_cart_show = 1'
|
|
. ' AND iq.eve_id = ' . $intEveId
|
|
. ' AND rq.pec_id = ' . $intPecId
|
|
. ' AND (rq.par_id = ' . $intParId . ' OR rq.par_id = ' . $intParIdOriginal . ')'
|
|
. ' AND rq.que_actif = 1'
|
|
. " AND TRIM(COALESCE(rq.que_choix_" . $strLangCol . ", '')) <> ''"
|
|
. ' ORDER BY iq.que_tri, iq.que_id';
|
|
|
|
$tabQuestionsRaw = $objDatabase->fxGetResults($sqlQuestions);
|
|
$tabQuestions = array();
|
|
|
|
if ($tabQuestionsRaw !== null) {
|
|
for ($i = 1; $i <= count($tabQuestionsRaw); $i++) {
|
|
$tabQ = $tabQuestionsRaw[$i];
|
|
$strLabel = trim(fxUnescape($tabQ['que_label']));
|
|
if ($strLabel === '') {
|
|
$strLabel = trim(fxUnescape($tabQ['que_question']));
|
|
}
|
|
$strValue = trim(fxUnescape($tabQ['que_choix']));
|
|
if ($strLabel === '' || $strValue === '') {
|
|
continue;
|
|
}
|
|
$tabQuestions[] = array(
|
|
'label' => $strLabel,
|
|
'value' => $strValue,
|
|
);
|
|
}
|
|
}
|
|
|
|
return array(
|
|
'bln_capitaine' => $blnCapitaine,
|
|
'email' => $strEmail,
|
|
'birth_gender' => $strBirthGender,
|
|
'questions' => $tabQuestions,
|
|
);
|
|
}
|
|
|
|
function fxInscrGestionRenderKvRowFlag($strText, $strExtraClass = '') {
|
|
$strClass = 'inscr-gestion-kv-row inscr-gestion-kv-row--flag';
|
|
if ($strExtraClass !== '') {
|
|
$strClass .= ' ' . $strExtraClass;
|
|
}
|
|
echo '<div class="' . fxInscrGestionEsc($strClass) . '">';
|
|
echo '<span class="inscr-gestion-kv-flag">' . fxInscrGestionEsc($strText) . '</span>';
|
|
echo '</div>';
|
|
}
|
|
|
|
function fxInscrGestionRenderFicheProfileKvRows($arrRow, $strLangue) {
|
|
$tabProfile = fxInscrGestionFetchFicheProfile($arrRow, $strLangue);
|
|
$blnFirstProfile = true;
|
|
$strProfileSep = 'inscr-gestion-kv-row--profile';
|
|
|
|
if ($tabProfile['bln_capitaine']) {
|
|
$strCaptainLabel = trim(fxInscrGestionT('participant-titre-capitaine'));
|
|
if ($strCaptainLabel === '') {
|
|
$strCaptainLabel = ($strLangue === 'fr') ? 'Capitaine' : 'Captain';
|
|
}
|
|
fxInscrGestionRenderKvRowFlag(
|
|
$strCaptainLabel,
|
|
$blnFirstProfile ? $strProfileSep : ''
|
|
);
|
|
$blnFirstProfile = false;
|
|
}
|
|
|
|
if ($tabProfile['email'] !== '') {
|
|
fxInscrGestionRenderKvRow(
|
|
fxInscrGestionT('inscr_gestion_email'),
|
|
$tabProfile['email'],
|
|
false,
|
|
$blnFirstProfile ? 'inscr-gestion-kv-row--profile' : ''
|
|
);
|
|
$blnFirstProfile = false;
|
|
}
|
|
|
|
if ($tabProfile['birth_gender'] !== '') {
|
|
fxInscrGestionRenderKvRow(
|
|
fxInscrGestionT('inscr_gestion_birthdate'),
|
|
$tabProfile['birth_gender'],
|
|
false,
|
|
$blnFirstProfile ? 'inscr-gestion-kv-row--profile' : ''
|
|
);
|
|
$blnFirstProfile = false;
|
|
}
|
|
|
|
foreach ($tabProfile['questions'] as $tabQuestion) {
|
|
fxInscrGestionRenderKvRow(
|
|
$tabQuestion['label'],
|
|
$tabQuestion['value'],
|
|
false,
|
|
$blnFirstProfile ? 'inscr-gestion-kv-row--profile' : ''
|
|
);
|
|
$blnFirstProfile = false;
|
|
}
|
|
}
|
|
|
|
/** Code statut course par défaut (Confirmé). */
|
|
function fxInscrGestionParStatutCourseDefault() {
|
|
return 'CONF';
|
|
}
|
|
|
|
function fxInscrGestionResolveParStatutCourse($strCurrent) {
|
|
$strCurrent = trim((string)$strCurrent);
|
|
return $strCurrent !== '' ? $strCurrent : fxInscrGestionParStatutCourseDefault();
|
|
}
|
|
|
|
/** Options statut course depuis info (info_description = opt). */
|
|
function fxInscrGestionGetStatutCourseOptions($strLangue) {
|
|
global $objDatabase;
|
|
|
|
static $tabCache = array();
|
|
if (isset($tabCache[$strLangue])) {
|
|
return $tabCache[$strLangue];
|
|
}
|
|
|
|
$sql = "SELECT info_texte, info_option2 FROM info"
|
|
. " WHERE info_actif = 1 AND info_clef = 'inscr_statut_course'"
|
|
. " AND info_langue = '" . $objDatabase->fxEscape($strLangue) . "'"
|
|
. " AND info_description = 'opt'"
|
|
. " ORDER BY info_trie";
|
|
$tabRows = $objDatabase->fxGetResults($sql);
|
|
$tabCache[$strLangue] = ($tabRows !== null) ? $tabRows : array();
|
|
|
|
return $tabCache[$strLangue];
|
|
}
|
|
|
|
function fxInscrGestionRenderStatutField($intParId, $strCurrent, $intEveId, $strLangue) {
|
|
$tabOptions = fxInscrGestionGetStatutCourseOptions($strLangue);
|
|
if (count($tabOptions) === 0) {
|
|
echo '<div class="inscr-gestion-muted">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_label')) . '</div>';
|
|
return;
|
|
}
|
|
|
|
$strCurrent = fxInscrGestionResolveParStatutCourse($strCurrent);
|
|
$strSelectId = 'inscr_statut_' . (int)$intParId;
|
|
|
|
echo '<select class="form-control rounded-0 inscr-gestion-statut-select" id="' . fxInscrGestionEsc($strSelectId) . '"'
|
|
. ' data-par_id="' . (int)$intParId . '"'
|
|
. ' data-eve_id="' . rawurlencode(base64_encode((string)$intEveId)) . '">';
|
|
|
|
foreach ($tabOptions as $arrOpt) {
|
|
$strCode = trim((string)$arrOpt['info_option2']);
|
|
$strLabel = trim((string)$arrOpt['info_texte']);
|
|
if ($strCode === '') {
|
|
continue;
|
|
}
|
|
|
|
echo '<option value="' . fxInscrGestionEsc($strCode) . '"'
|
|
. ($strCurrent === $strCode ? ' selected' : '') . '>'
|
|
. fxInscrGestionEsc($strLabel) . '</option>';
|
|
}
|
|
|
|
echo '</select>';
|
|
}
|
|
|
|
/** Paramètres GET pour liens (sans double-encodage). */
|
|
function fxInscrGestionQueryParams($intEveId, $arrReq, $arrExtra = array()) {
|
|
$tab = array(
|
|
'promoteur_eve_id' => base64_encode((string)$intEveId),
|
|
);
|
|
|
|
if ($arrReq['rech_prenom'] !== '') {
|
|
$tab['rech_prenom'] = $arrReq['rech_prenom'];
|
|
}
|
|
if ($arrReq['rech_nom'] !== '') {
|
|
$tab['rech_nom'] = $arrReq['rech_nom'];
|
|
}
|
|
if ($arrReq['rech_no_commande'] !== '') {
|
|
$tab['rech_no_commande'] = $arrReq['rech_no_commande'];
|
|
}
|
|
if ($arrReq['rech_nom_equipe'] !== '') {
|
|
$tab['rech_nom_equipe'] = $arrReq['rech_nom_equipe'];
|
|
}
|
|
if ($arrReq['chk_bib']) {
|
|
$tab['chk_bib'] = 1;
|
|
}
|
|
if ($arrReq['chk_cancelled']) {
|
|
$tab['chk_cancelled'] = 1;
|
|
}
|
|
if ($arrReq['sel_rech_epreuve'] > 0) {
|
|
$tab['sel_rech_epreuve'] = base64_encode((string)$arrReq['sel_rech_epreuve']);
|
|
}
|
|
if (!empty($_GET['lng'])) {
|
|
$tab['lng'] = $_GET['lng'];
|
|
}
|
|
if (!empty($arrReq['q'])) {
|
|
// Transporte l'etat "recherche lancee" pour que la pagination et le retour de fiche gardent la liste.
|
|
$tab['q'] = 1;
|
|
}
|
|
if (!empty($arrReq['pg']) && (int)$arrReq['pg'] > 1) {
|
|
$tab['pg'] = (int)$arrReq['pg'];
|
|
}
|
|
|
|
foreach ($arrExtra as $strKey => $mixVal) {
|
|
if ($mixVal === null || $mixVal === '' || ($strKey === 'pec_id' && (int)$mixVal === 0)) {
|
|
unset($tab[$strKey]);
|
|
} else {
|
|
$tab[$strKey] = $mixVal;
|
|
}
|
|
}
|
|
|
|
return $tab;
|
|
}
|
|
|
|
function fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, $arrExtra = array()) {
|
|
$tab = fxInscrGestionQueryParams($intEveId, $arrReq, $arrExtra);
|
|
$strQs = http_build_query($tab, '', '&');
|
|
|
|
return $strBaseUrl . ($strQs !== '' ? '?' . $strQs : '');
|
|
}
|
|
|
|
function fxInscrGestionPaginationUrl($strBaseUrl, $intEveId, $arrReq) {
|
|
$tab = fxInscrGestionQueryParams($intEveId, $arrReq, array('pec_id' => null));
|
|
unset($tab['pg'], $tab['pec_id']);
|
|
$strQs = http_build_query($tab, '', '&');
|
|
|
|
return $strBaseUrl . ($strQs !== '' ? '?' . $strQs : '?promoteur_eve_id=' . rawurlencode(base64_encode((string)$intEveId)));
|
|
}
|
|
|
|
function fxInscrGestionRenderPagination($strBaseUrl, $intEveId, $arrReq, $intTotal, $intPerPage, $intPage) {
|
|
if ($intTotal <= $intPerPage) {
|
|
return '';
|
|
}
|
|
|
|
return '<div class="inscr-gestion-pager">'
|
|
. fxGetPagination(
|
|
fxInscrGestionPaginationUrl($strBaseUrl, $intEveId, $arrReq),
|
|
$intTotal,
|
|
$intPerPage,
|
|
$intPage
|
|
)
|
|
. '</div>';
|
|
}
|
|
|
|
function fxInscrGestionExtractQrToken($strRaw) {
|
|
$strRaw = trim((string)$strRaw);
|
|
if ($strRaw === '') {
|
|
return '';
|
|
}
|
|
|
|
if (preg_match('/[?&]t=([^&\s#]+)/', $strRaw, $tabMatch)) {
|
|
return urldecode($tabMatch[1]);
|
|
}
|
|
|
|
if (preg_match('/^https?:\/\//i', $strRaw)) {
|
|
$tabParts = parse_url($strRaw);
|
|
if (!empty($tabParts['query'])) {
|
|
parse_str($tabParts['query'], $tabQuery);
|
|
if (!empty($tabQuery['t'])) {
|
|
return trim((string)$tabQuery['t']);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (preg_match('/^[a-zA-Z0-9_-]{6,64}$/', $strRaw)) {
|
|
return $strRaw;
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function fxInscrGestionResolveQrScan($strRaw, $intEveId, $strLangue) {
|
|
global $objDatabase;
|
|
|
|
$strToken = fxInscrGestionExtractQrToken($strRaw);
|
|
if ($strToken === '') {
|
|
return array('state' => 'error', 'message' => fxInscrGestionT('inscr_gestion_qr_invalid'));
|
|
}
|
|
|
|
$tabToken = $objDatabase->fxGetRow(
|
|
'SELECT qr_public_id, pec_id_original, eve_id'
|
|
. ' FROM qr_tokens'
|
|
. " WHERE qr_public_id = '" . $objDatabase->fxEscape($strToken) . "'"
|
|
. ' LIMIT 1'
|
|
);
|
|
|
|
if ($tabToken === null) {
|
|
return array('state' => 'error', 'message' => fxInscrGestionT('inscr_gestion_qr_invalid'));
|
|
}
|
|
|
|
$intPecId = (int)$tabToken['pec_id_original'];
|
|
if ($intPecId <= 0) {
|
|
return array('state' => 'error', 'message' => fxInscrGestionT('inscr_gestion_qr_invalid'));
|
|
}
|
|
|
|
$tabPec = $objDatabase->fxGetRow(
|
|
'SELECT ec.pec_id_original'
|
|
. ' FROM resultats_epreuves_commandees ec'
|
|
. ' WHERE ec.pec_id_original = ' . $intPecId
|
|
. ' AND ec.eve_id = ' . intval($intEveId)
|
|
. ' AND ec.pec_actif = 1'
|
|
. ' LIMIT 1'
|
|
);
|
|
|
|
if ($tabPec !== null) {
|
|
$arrRow = fxInscrGestionFetchRowByPec($intPecId, $intEveId);
|
|
if ($arrRow === null) {
|
|
return array('state' => 'error', 'message' => fxInscrGestionT('inscr_gestion_qr_not_found'));
|
|
}
|
|
|
|
return array(
|
|
'state' => 'success',
|
|
'pec_id' => $intPecId,
|
|
);
|
|
}
|
|
|
|
$intQrEveId = (int)$tabToken['eve_id'];
|
|
if ($intQrEveId <= 0) {
|
|
$tabOther = $objDatabase->fxGetRow(
|
|
'SELECT ec.eve_id FROM resultats_epreuves_commandees ec'
|
|
. ' WHERE ec.pec_id_original = ' . $intPecId
|
|
. ' AND ec.pec_actif = 1'
|
|
. ' ORDER BY ec.pec_id_original DESC LIMIT 1'
|
|
);
|
|
if ($tabOther !== null) {
|
|
$intQrEveId = (int)$tabOther['eve_id'];
|
|
}
|
|
}
|
|
|
|
$strEveNom = '';
|
|
if ($intQrEveId > 0) {
|
|
$arrEv = fxGetEvenementsId($intQrEveId);
|
|
if (!empty($arrEv)) {
|
|
$strEveNom = fxUnescape($arrEv['eve_nom_' . $strLangue]);
|
|
}
|
|
}
|
|
|
|
if ($strEveNom === '') {
|
|
$strEveNom = '#' . $intQrEveId;
|
|
}
|
|
|
|
return array(
|
|
'state' => 'wrong_event',
|
|
'message' => str_replace('%s', $strEveNom, fxInscrGestionT('inscr_gestion_qr_wrong_event')),
|
|
'eve_nom' => $strEveNom,
|
|
);
|
|
}
|
|
|
|
function fxInscrGestionRenderEventPicker($tabEveIds, $strLangue, $strBaseUrl) {
|
|
global $objDatabase;
|
|
|
|
$strTitle = ($strLangue === 'fr') ? 'Choisir un événement' : 'Choose an event';
|
|
|
|
echo '<div id="module-inscr-gestion" class="inscr-gestion-shell">';
|
|
fxInscrGestionRenderPageHead($strTitle);
|
|
echo '<div class="inscr-gestion-event-list">';
|
|
|
|
foreach ($tabEveIds as $intEveId) {
|
|
$qry = 'SELECT e.* FROM inscriptions_evenements e WHERE e.eve_actif = 1 AND e.eve_id = ' . intval($intEveId);
|
|
$tabEv = $objDatabase->fxGetRow($qry);
|
|
if ($tabEv === null) {
|
|
continue;
|
|
}
|
|
|
|
$strUrl = fxInscrGestionBuildUrl($strBaseUrl, $intEveId, fxInscrGestionParseRequest(), array());
|
|
echo '<a class="inscr-gestion-event-item" href="' . fxInscrGestionEsc($strUrl) . '">';
|
|
echo '<span class="inscr-gestion-event-item__name">' . fxInscrGestionEsc(fxUnescape($tabEv['eve_nom_' . $strLangue])) . '</span>';
|
|
echo '<i class="fa fa-chevron-right" aria-hidden="true"></i>';
|
|
echo '</a>';
|
|
}
|
|
|
|
echo '</div></div>';
|
|
}
|
|
|
|
function fxInscrGestionRenderQrPanel($intEveId, $strLangue) {
|
|
global $vDomaine;
|
|
|
|
$intComId = intval($_SESSION['com_id'] ?? 0);
|
|
if (!fxInscrGestionCanScan($intComId, $intEveId)) {
|
|
return;
|
|
}
|
|
|
|
$strQrAjaxUrl = $vDomaine . '/ajax_inscr_gestion_qr.php';
|
|
|
|
echo '<details class="inscr-gestion-panel inscr-gestion-panel--qr" id="inscr-gestion-qr-panel"';
|
|
echo ' data-qr-resolve-url="' . fxInscrGestionEsc($strQrAjaxUrl) . '"';
|
|
echo ' data-qr-eve-id="' . fxInscrGestionEsc(base64_encode((string)$intEveId)) . '"';
|
|
echo ' data-qr-lang="' . fxInscrGestionEsc($strLangue) . '"';
|
|
echo ' data-qr-msg-invalid="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_qr_invalid')) . '"';
|
|
echo ' data-qr-msg-wrong="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_qr_wrong_event')) . '"';
|
|
echo ' data-qr-msg-camera="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_qr_camera_error')) . '">';
|
|
echo '<summary class="inscr-gestion-panel__head">';
|
|
fxInscrGestionRenderPanelSummary(fxInscrGestionT('inscr_gestion_qr_title'), 'fa-qrcode');
|
|
echo '</summary>';
|
|
echo '<div class="inscr-gestion-panel__body">';
|
|
echo '<p class="inscr-gestion-qr-hint text-muted small mb-2">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_qr_hint')) . '</p>';
|
|
echo '<div id="inscr-gestion-qr-feedback" class="alert d-none mb-2" role="alert"></div>';
|
|
echo '<div id="inscr-gestion-qr-reader-wrap" class="inscr-gestion-qr-reader-wrap">';
|
|
echo '<div id="inscr-gestion-qr-reader"></div>';
|
|
echo '</div></div></details>';
|
|
}
|
|
|
|
function fxInscrGestionRenderBibScanBlock($strBibInputId, $strLangue) {
|
|
echo '<div class="inscr-gestion-bib-scan-panel" hidden';
|
|
echo ' data-bib-input-id="' . fxInscrGestionEsc($strBibInputId) . '"';
|
|
echo ' data-msg-scanning="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_scanning')) . '"';
|
|
echo ' data-msg-loading="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_loading')) . '"';
|
|
echo ' data-msg-ready="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_ready')) . '"';
|
|
echo ' data-msg-found="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_found')) . '"';
|
|
echo ' data-msg-invalid="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_invalid')) . '"';
|
|
echo ' data-msg-camera="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_qr_camera_error')) . '">';
|
|
echo '<p class="inscr-gestion-bib-scan-hint text-muted small mb-1">' . fxInscrGestionEsc(fxInscrGestionScanLabel('inscr_gestion_bib_scan_hint')) . '</p>';
|
|
echo '<div class="inscr-gestion-bib-scan-status small mb-1" aria-live="polite"></div>';
|
|
echo '<div class="inscr-gestion-bib-scan-capture" role="button" tabindex="0">';
|
|
echo '<div class="inscr-gestion-bib-scan-video"></div>';
|
|
// Zone-cible centrale (eclaircie) : aligne le repere visuel sur la region
|
|
// reellement lue par l'OCR (captureCenterFrame : ~55% largeur x 30% hauteur).
|
|
echo '<div class="inscr-gestion-bib-scan-target" aria-hidden="true"></div>';
|
|
echo '<span class="inscr-gestion-bib-scan-capture-label">' . fxInscrGestionEsc(fxInscrGestionScanLabel('inscr_gestion_bib_scan_tap')) . '</span>';
|
|
echo '</div>';
|
|
echo '</div>';
|
|
}
|
|
|
|
function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
|
|
global $vDomaine;
|
|
|
|
$arrEvenement = fxGetEvenementsId($intEveId);
|
|
$strEveNom = fxUnescape($arrEvenement['eve_nom_' . $strLangue]);
|
|
$intFilterCount = fxInscrGestionFilterActiveCount($arrReq);
|
|
// La page arrive vide : on n'affiche les resultats qu'apres une recherche (meme vide = tout afficher).
|
|
$blnSearchActive = !empty($arrReq['q']);
|
|
$blnFreshSearch = !empty($_GET['btn_recherche']) || !empty($_GET['apply_filters']);
|
|
$tabRows = null;
|
|
|
|
// Un seul resultat apres soumission : redirection JS (header() impossible ici, la page est deja entamee).
|
|
if ($blnSearchActive && $blnFreshSearch) {
|
|
$tabRows = fxInscrGestionFetchRows($intEveId, $arrReq);
|
|
if ($tabRows !== null && count($tabRows) === 1) {
|
|
$strFicheUrl = fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array(
|
|
'pec_id' => (int)$tabRows[1]['pec_id_original'],
|
|
'pg' => 1,
|
|
));
|
|
echo '<div id="module-inscr-gestion" class="inscr-gestion-shell" data-inscr-gestion="1">';
|
|
echo '<script>window.location.replace(' . json_encode($strFicheUrl, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE) . ');</script>';
|
|
echo '<noscript><meta http-equiv="refresh" content="0;url=' . fxInscrGestionEsc($strFicheUrl) . '"></noscript>';
|
|
echo '</div>';
|
|
return;
|
|
}
|
|
}
|
|
|
|
$strBackUrl = fxInscrGestionIsEntry()
|
|
? $strBaseUrl
|
|
: ($vDomaine . ($strLangue === 'fr' ? '/compte/inc_tableau_promoteur' : '/account/inc_tableau_promoteur')
|
|
. '?promoteur_eve_id=' . rawurlencode(base64_encode((string)$intEveId)));
|
|
|
|
echo '<div id="module-inscr-gestion" class="inscr-gestion-shell" data-inscr-gestion="1">';
|
|
|
|
if (fxInscrGestionShouldShowListBack((int)$_SESSION['com_id'])) {
|
|
fxInscrGestionRenderNavBack($strBackUrl, fxInscrGestionListBackLabel($strLangue));
|
|
}
|
|
fxInscrGestionRenderPageHead(fxInscrGestionT('inscr_gestion_title'), $strEveNom);
|
|
|
|
fxInscrGestionRenderQrPanel($intEveId, $strLangue);
|
|
|
|
// Recherche (repliable — ouverte par défaut tant qu'aucune recherche n'a été lancée, car la liste arrive vide)
|
|
echo '<details class="inscr-gestion-panel"' . ($blnSearchActive ? '' : ' open') . '>';
|
|
echo '<summary class="inscr-gestion-panel__head">';
|
|
fxInscrGestionRenderPanelSummary(fxInscrGestionT('txt_recherche'), 'fa-search');
|
|
echo '</summary>';
|
|
echo '<div class="inscr-gestion-panel__body">';
|
|
echo '<form action="' . fxInscrGestionEsc($strBaseUrl) . '" method="get" class="inscr-gestion-form">';
|
|
echo '<input type="hidden" name="promoteur_eve_id" value="' . fxInscrGestionEsc(base64_encode((string)$intEveId)) . '">';
|
|
|
|
$arrFields = array(
|
|
'rech_prenom' => 'rech_prenom',
|
|
'rech_nom' => 'rech_nom',
|
|
'rech_no_commande' => 'rech_no_commande',
|
|
'rech_nom_equipe' => 'inscr_gestion_rech_bib_equipe',
|
|
);
|
|
foreach ($arrFields as $strKey => $strLbl) {
|
|
echo '<label class="inscr-gestion-label" for="' . $strKey . '">' . fxInscrGestionEsc(fxInscrGestionT($strLbl)) . '</label>';
|
|
if ($strKey === 'rech_nom_equipe') {
|
|
echo '<div class="inscr-gestion-field-block inscr-gestion-field-block--search-bib" data-inscr-field="bib">';
|
|
fxInscrGestionRenderBibScanBlock($strKey, $strLangue);
|
|
echo '<div class="inscr-gestion-bib-row">';
|
|
echo '<input class="form-control form-control-sm rounded-0" type="text" id="' . $strKey . '" name="' . $strKey . '" value="' . fxInscrGestionEsc($arrReq[$strKey]) . '">';
|
|
echo '<button class="btn btn-secondary btn-sm rounded-0 inscr-gestion-bib-scan-toggle" type="button" aria-expanded="false"'
|
|
. ' title="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_btn')) . '"'
|
|
. ' aria-label="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_btn')) . '">';
|
|
echo '<i class="fa fa-camera" aria-hidden="true"></i>';
|
|
echo '</button>';
|
|
echo '</div></div>';
|
|
continue;
|
|
}
|
|
echo '<input class="form-control form-control-sm rounded-0" type="text" id="' . $strKey . '" name="' . $strKey . '" value="' . fxInscrGestionEsc($arrReq[$strKey]) . '">';
|
|
}
|
|
|
|
if ($arrReq['sel_rech_epreuve'] > 0) {
|
|
echo '<input type="hidden" name="sel_rech_epreuve" value="' . fxInscrGestionEsc(base64_encode((string)$arrReq['sel_rech_epreuve'])) . '">';
|
|
}
|
|
if ($arrReq['chk_bib']) {
|
|
echo '<input type="hidden" name="chk_bib" value="1">';
|
|
}
|
|
if ($arrReq['chk_cancelled']) {
|
|
echo '<input type="hidden" name="chk_cancelled" value="1">';
|
|
}
|
|
|
|
echo '<div class="inscr-gestion-form-actions mt-2">';
|
|
echo '<a class="btn btn-secondary btn-sm rounded-0" href="' . fxInscrGestionEsc(fxInscrGestionSearchResetUrl($strBaseUrl, $intEveId)) . '">'
|
|
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_reset_search')) . '</a>';
|
|
echo '<button class="btn btn-primary btn-sm rounded-0" type="submit" name="btn_recherche" value="1">' . fxInscrGestionEsc(fxInscrGestionT('txt_recherche')) . '</button>';
|
|
echo '</div></form></div></details>';
|
|
|
|
// Filtres
|
|
global $objDatabase;
|
|
$tabEpreuves = $objDatabase->fxGetResults(
|
|
'SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = ' . intval($intEveId) . ' AND epr_actif = 1 ORDER BY epr_id'
|
|
);
|
|
|
|
$strFilterLabel = fxInscrGestionT('inscr_gestion_filters');
|
|
if ($intFilterCount > 0) {
|
|
$strFilterLabel .= ' (' . $intFilterCount . ')';
|
|
}
|
|
|
|
echo '<details class="inscr-gestion-panel">';
|
|
echo '<summary class="inscr-gestion-panel__head">';
|
|
fxInscrGestionRenderPanelSummary($strFilterLabel, 'fa-filter');
|
|
echo '</summary>';
|
|
echo '<div class="inscr-gestion-panel__body">';
|
|
echo '<form action="' . fxInscrGestionEsc($strBaseUrl) . '" method="get" class="inscr-gestion-form">';
|
|
echo '<input type="hidden" name="promoteur_eve_id" value="' . fxInscrGestionEsc(base64_encode((string)$intEveId)) . '">';
|
|
|
|
foreach (array('rech_prenom', 'rech_nom', 'rech_no_commande', 'rech_nom_equipe') as $strKey) {
|
|
if ($arrReq[$strKey] !== '') {
|
|
echo '<input type="hidden" name="' . $strKey . '" value="' . fxInscrGestionEsc($arrReq[$strKey]) . '">';
|
|
}
|
|
}
|
|
|
|
echo '<label class="inscr-gestion-label" for="sel_rech_epreuve">' . fxInscrGestionEsc(fxInscrGestionT('sel_rech_epreuve')) . '</label>';
|
|
echo '<select class="form-control form-control-sm rounded-0" id="sel_rech_epreuve" name="sel_rech_epreuve">';
|
|
echo '<option value="">—</option>';
|
|
for ($i = 1; $i <= count($tabEpreuves); $i++) {
|
|
$strOpt = fxInscrGestionEpreuveLabel($tabEpreuves[$i]['epr_id'], $strLangue);
|
|
$strSel = ($arrReq['sel_rech_epreuve'] == $tabEpreuves[$i]['epr_id']) ? ' selected' : '';
|
|
$strVal = base64_encode((string)$tabEpreuves[$i]['epr_id']);
|
|
echo '<option value="' . fxInscrGestionEsc($strVal) . '"' . $strSel . '>' . fxInscrGestionEsc($strOpt) . '</option>';
|
|
}
|
|
echo '</select>';
|
|
|
|
echo '<label class="inscr-gestion-check mt-2"><input type="checkbox" name="chk_bib" value="1"' . ($arrReq['chk_bib'] ? ' checked' : '') . '> ' . fxInscrGestionEsc(fxInscrGestionT('chk_bib')) . '</label>';
|
|
echo '<label class="inscr-gestion-check"><input type="checkbox" name="chk_cancelled" value="1"' . ($arrReq['chk_cancelled'] ? ' checked' : '') . '> ' . fxInscrGestionEsc(fxInscrGestionT('chk_cancelled')) . '</label>';
|
|
|
|
echo '<div class="inscr-gestion-form-actions mt-2">';
|
|
echo '<a class="btn btn-secondary btn-sm rounded-0" href="' . fxInscrGestionEsc(fxInscrGestionSearchResetUrl($strBaseUrl, $intEveId)) . '">'
|
|
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_reset_search')) . '</a>';
|
|
echo '<button class="btn btn-primary btn-sm rounded-0" type="submit" name="apply_filters" value="1">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_apply_filters')) . '</button>';
|
|
echo '</div></form></div></details>';
|
|
|
|
echo '<div id="inscr-gestion-list" class="inscr-gestion-list-anchor">';
|
|
|
|
// Tant qu'aucune recherche n'a été lancée, on n'affiche aucune inscription : seulement une invite.
|
|
if (!$blnSearchActive) {
|
|
echo '<div class="alert alert-light border inscr-gestion-empty">'
|
|
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_search_prompt')) . '</div>';
|
|
echo '</div>';
|
|
return;
|
|
}
|
|
|
|
// Résultats (la recherche a été lancée — une recherche vide affiche toutes les inscriptions).
|
|
if ($tabRows === null) {
|
|
$tabRows = fxInscrGestionFetchRows($intEveId, $arrReq);
|
|
}
|
|
$intNbItemsParPage = 50;
|
|
$intNbTotal = ($tabRows !== null) ? count($tabRows) : 0;
|
|
$intPage = 1;
|
|
$intStart = 1;
|
|
$intEnd = $intNbItemsParPage;
|
|
if (!empty($_GET['pg'])) {
|
|
$intPage = max(1, intval($_GET['pg']));
|
|
}
|
|
if (intval($intPage) > 1) {
|
|
$intStart = ($intPage - 1) * $intNbItemsParPage + 1;
|
|
$intEnd = $intStart + $intNbItemsParPage - 1;
|
|
}
|
|
if ($intEnd > $intNbTotal) {
|
|
$intEnd = $intNbTotal;
|
|
}
|
|
|
|
echo '<div class="inscr-gestion-list-head">';
|
|
if ($strLangue === 'fr') {
|
|
echo '<span>' . (int)$intNbTotal . ' inscription' . ($intNbTotal > 1 ? 's' : '') . '</span>';
|
|
} else {
|
|
echo '<span>' . (int)$intNbTotal . ' registration' . ($intNbTotal !== 1 ? 's' : '') . '</span>';
|
|
}
|
|
if ($intNbTotal > $intNbItemsParPage) {
|
|
$intNbPages = (int)ceil($intNbTotal / $intNbItemsParPage);
|
|
echo '<span class="inscr-gestion-list-head__pg">' . ($strLangue === 'fr' ? 'Page ' : 'Page ') . $intPage . ' / ' . $intNbPages . '</span>';
|
|
}
|
|
echo '</div>';
|
|
|
|
if ($intNbTotal > 0) {
|
|
echo '<div class="inscr-gestion-list">';
|
|
|
|
// En-tete de colonnes (memes colonnes que les lignes ; masque en vue cellulaire,
|
|
// ou la liste passe en cartes). aria-hidden : purement visuel, redondant pour les
|
|
// lecteurs d'ecran car chaque valeur de ligne porte deja son sens.
|
|
echo '<div class="inscr-gestion-list-cols" aria-hidden="true">';
|
|
if ($strLangue === 'fr') {
|
|
echo '<span>Participant</span>';
|
|
echo '<span>Épreuve</span>';
|
|
echo '<span>Commande</span>';
|
|
echo '<span class="inscr-gestion-list-cols__bib">Dossard</span>';
|
|
echo '<span class="inscr-gestion-list-cols__check">Remis</span>';
|
|
} else {
|
|
echo '<span>Participant</span>';
|
|
echo '<span>Race</span>';
|
|
echo '<span>Order</span>';
|
|
echo '<span class="inscr-gestion-list-cols__bib">Bib</span>';
|
|
echo '<span class="inscr-gestion-list-cols__check">Issued</span>';
|
|
}
|
|
echo '<span></span>';
|
|
echo '</div>';
|
|
|
|
for ($j = $intStart; $j <= $intEnd; $j++) {
|
|
$row = $tabRows[$j];
|
|
$strFicheUrl = fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array(
|
|
'pec_id' => (int)$row['pec_id_original'],
|
|
'pg' => $intPage,
|
|
));
|
|
|
|
$strBib = fxInscrGestionBibDisplay($row);
|
|
$strName = fxUnescape($row['par_nom']) . ', ' . fxUnescape($row['par_prenom']);
|
|
$strRace = fxInscrGestionEpreuveLabel($row['epr_id'], $strLangue);
|
|
$strCardClass = 'inscr-gestion-list-item';
|
|
$strCancelBadge = '';
|
|
if ($row['is_cancelled'] == '1') {
|
|
// MSIN-4405 — Cause derivee en lecture seule (aucune ecriture en base).
|
|
$strCause = fxGetAnnulationCause($row['pec_id_original'], $row['pec_actif']);
|
|
$strCardClass .= ' inscr-gestion-list-item--cancelled inscr-gestion-list-item--' . $strCause;
|
|
$strCancelBadge = ' <span class="inscr-gestion-cancel-badge inscr-gestion-cancel-badge--' . $strCause . '">'
|
|
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_' . $strCause)) . '</span>';
|
|
}
|
|
|
|
echo '<a class="' . $strCardClass . '" href="' . fxInscrGestionEsc($strFicheUrl) . '">';
|
|
echo '<span class="inscr-gestion-list-item__name">' . fxInscrGestionEsc($strName) . $strCancelBadge . '</span>';
|
|
echo '<span class="inscr-gestion-list-item__race">' . fxInscrGestionEsc($strRace) . '</span>';
|
|
echo '<span class="inscr-gestion-list-item__order">' . fxInscrGestionEsc($row['no_commande']) . '</span>';
|
|
echo '<span class="inscr-gestion-list-item__bib">';
|
|
echo trim($strBib) !== '' ? fxInscrGestionEsc($strBib) : '—';
|
|
echo '</span>';
|
|
echo '<span class="inscr-gestion-list-item__check">';
|
|
if ($row['no_bib_remis'] == 1) {
|
|
echo '<span class="inscr-gestion-badge inscr-gestion-badge--ok">' . fxInscrGestionEsc(fxInscrGestionT('promoteur_bib_enregistre')) . '</span>';
|
|
}
|
|
echo '</span>';
|
|
echo '<i class="fa fa-chevron-right inscr-gestion-list-item__arrow" aria-hidden="true"></i>';
|
|
echo '</a>';
|
|
}
|
|
echo '</div>';
|
|
|
|
echo fxInscrGestionRenderPagination($strBaseUrl, $intEveId, $arrReq, $intNbTotal, $intNbItemsParPage, $intPage);
|
|
} else {
|
|
echo '<div class="alert alert-light border inscr-gestion-empty">' . fxInscrGestionEsc(fxInscrGestionT('txt_recherche_no_result')) . '</div>';
|
|
}
|
|
|
|
echo '</div>';
|
|
}
|
|
|
|
function fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq, $arrRow) {
|
|
global $vDomaine;
|
|
|
|
$intComId = intval($_SESSION['com_id'] ?? 0);
|
|
$intRowEveId = intval($arrRow['eve_id']);
|
|
$blnCanStatut = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.statut_edit');
|
|
$blnCanBib = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.bib_edit');
|
|
$blnCanRemis = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.bib_remis');
|
|
$blnCanEdit = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.edit');
|
|
$blnCanCancel = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.cancel');
|
|
$blnCanRestore = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.restore');
|
|
// Droit de remboursement PayPal (etape remboursement) : controle l'affichage du bouton + panneau.
|
|
$blnCanRefund = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.refund');
|
|
$blnHasEditable = ($blnCanStatut || $blnCanBib || $blnCanRemis);
|
|
$blnHasGestion = ($blnCanEdit || $blnCanCancel || $blnCanRestore || $blnCanRefund);
|
|
$blnInspect = function_exists('fxAdminPermInspectModeActive') && fxAdminPermInspectModeActive();
|
|
|
|
$strListUrl = fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null, 'pg' => $arrReq['pg']));
|
|
$strEveCode = fxGetEvenementsUrl($arrRow['eve_id']);
|
|
$strBib = fxInscrGestionBibDisplay($arrRow);
|
|
$intParId = $arrRow['par_id'];
|
|
$blnCancelled = ($arrRow['is_cancelled'] == '1');
|
|
$blnEquipe = (intval($arrRow['pec_equipe']) === 1);
|
|
$strBibAction = $blnEquipe ? 'no_equipe' : 'no_bib';
|
|
$strBibInputId = $blnEquipe ? 'txt_no_bib_e' : 'txt_no_bib_p';
|
|
|
|
if ($arrRow['no_bib_remis'] == 1) {
|
|
$strRemisClass = 'btn-success';
|
|
$strRemisIcon = '<i class="fa fa-check" aria-hidden="true"></i>';
|
|
$intRemisVal = 0;
|
|
} else {
|
|
$strRemisClass = 'btn-primary';
|
|
$strRemisIcon = '<i class="fa fa-sharp fa-regular fa-square fa-2xs" aria-hidden="true"></i>';
|
|
$intRemisVal = 1;
|
|
}
|
|
|
|
echo '<div id="module-inscr-gestion" class="inscr-gestion-shell inscr-gestion-fiche" data-inscr-gestion="1"';
|
|
$blnFromQr = !empty($_GET['from_qr']);
|
|
if ($blnFromQr) {
|
|
echo ' data-from-qr="1"';
|
|
}
|
|
echo '>';
|
|
|
|
fxInscrGestionRenderNavBack($strListUrl, fxInscrGestionT('inscr_gestion_back_list'));
|
|
echo '<div class="inscr-gestion-fiche-head">';
|
|
echo '<h1 class="inscr-gestion-page-title">' . fxInscrGestionEsc(fxUnescape($arrRow['par_nom']) . ', ' . fxUnescape($arrRow['par_prenom'])) . '</h1>';
|
|
echo '</div>';
|
|
|
|
$strDetailsType = $blnEquipe && fxIsParEquipe($arrRow['pec_id_original'], $arrRow['epr_id'])
|
|
? fxInscrGestionT('promoteur_bib_show_teamates')
|
|
: fxInscrGestionT('epreuve_individuelle');
|
|
|
|
fxInscrGestionRenderFicheSectionStart('details', fxInscrGestionT('inscr_gestion_details'), 'fa-info-circle', !$blnFromQr);
|
|
fxInscrGestionRenderKvListOpen();
|
|
fxInscrGestionRenderKvRow(fxInscrGestionT('inscr_gestion_epreuve'), fxInscrGestionEpreuveLabel($arrRow['epr_id'], $strLangue));
|
|
fxInscrGestionRenderKvRow(fxInscrGestionT('inscr_gestion_type'), $strDetailsType);
|
|
if ($blnCancelled) {
|
|
// MSIN-4405 — Detail de l'annulation (transfere / modifie / annule) derive en lecture seule.
|
|
$strCause = fxGetAnnulationCause($arrRow['pec_id_original'], $arrRow['pec_actif']);
|
|
fxInscrGestionRenderKvRow(
|
|
fxInscrGestionT('inscr_gestion_annulation_titre'),
|
|
'<span class="inscr-gestion-cancel-badge inscr-gestion-cancel-badge--' . $strCause . '">'
|
|
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_' . $strCause)) . '</span>',
|
|
true
|
|
);
|
|
}
|
|
fxInscrGestionRenderKvRow(fxInscrGestionT('inscr_gestion_modified'), fxCheckMAJ($arrRow['pec_id_original'], $intParId, $strLangue), true);
|
|
fxInscrGestionRenderFicheProfileKvRows($arrRow, $strLangue);
|
|
fxInscrGestionRenderKvListClose();
|
|
fxInscrGestionRenderFicheSectionEnd();
|
|
|
|
$strStyleEdit = $strStyleCancel = '';
|
|
$strStyleRetablir = ' d-none';
|
|
if ($blnCancelled) {
|
|
$strStyleEdit = $strStyleCancel = ' d-none';
|
|
$strStyleRetablir = '';
|
|
}
|
|
// Libelle du bouton de renvoi (facture/invitation) : passe par la table info pour etre editable.
|
|
$strRenvoi = fxInscrGestionT('inscr_gestion_renvoi');
|
|
|
|
if ($blnHasGestion || $blnInspect) {
|
|
fxInscrGestionRenderFicheSectionStart('gestion', fxInscrGestionT('inscr_gestion_section_management'), 'fa-cog', !$blnFromQr);
|
|
echo '<div class="inscr-gestion-gestion-actions">';
|
|
// Libelle devant le bouton facture (numero de commande) — invite a afficher la facture.
|
|
echo '<span class="inscr-gestion-facture-label">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_show_invoice')) . '</span>';
|
|
echo '<a class="btn btn-primary btn-sm rounded-pill" href="' . $vDomaine . '/facture.php?no_panier=' . rawurlencode($arrRow['no_panier']) . '&lang=' . $strLangue . '" target="_blank">' . fxInscrGestionEsc($arrRow['no_commande']) . '</a>';
|
|
// Bascule "Afficher la transaction" (MSIN) : place entre le numero de transaction et Modifier.
|
|
// Charge le resume de la commande en AJAX (action transaction_resume) dans le panneau ci-dessous.
|
|
echo '<button class="btn btn-info btn-sm rounded-0 btn_transaction_toggle" type="button"'
|
|
. ' data-no_panier="' . fxInscrGestionEsc($arrRow['no_panier']) . '"'
|
|
. ' data-transaction-target="#inscr-gestion-transaction-panel"'
|
|
. ' data-label-show="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_show_transaction')) . '"'
|
|
. ' data-label-hide="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_hide_transaction')) . '"'
|
|
. ' aria-expanded="false">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_show_transaction')) . '</button>';
|
|
if ($blnCanEdit) {
|
|
echo '<button class="btn btn-primary btn-sm rounded-0 btn_edit_event_promo' . $strStyleEdit . '" type="button"'
|
|
. ' id="modifier_fiche" data-eve_code="' . fxInscrGestionEsc($strEveCode) . '"'
|
|
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '" data-eve_id="' . (int)$arrRow['eve_id'] . '"'
|
|
. ' value="' . (int)$arrRow['pec_id_original'] . '">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_modifier_participant')) . '</button>';
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.edit');
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.edit', fxInscrGestionT('inscr_gestion_modifier_participant'));
|
|
}
|
|
if ($blnCanRefund) {
|
|
// Bouton bascule : ouvre/ferme le panneau de remboursement et declenche le chargement AJAX du formulaire.
|
|
echo '<button class="btn btn-warning btn-sm rounded-0 btn_refund_toggle" type="button"'
|
|
. ' data-inscr-field="remboursement"'
|
|
. ' data-no_panier="' . fxInscrGestionEsc($arrRow['no_panier']) . '"'
|
|
. ' data-eve_id="' . (int)$intRowEveId . '"'
|
|
. ' data-refund-target="#inscr-gestion-refund-panel"'
|
|
. ' aria-expanded="false">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_remboursement')) . '</button>';
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.refund');
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.refund', fxInscrGestionT('inscr_gestion_remboursement'));
|
|
}
|
|
if ($blnCanCancel) {
|
|
echo '<button class="btn btn-secondary btn-sm rounded-0 btn_cancel_event_promo' . $strStyleCancel . '" type="button"'
|
|
. ' id="annuler_fiche" data-eve_code="' . fxInscrGestionEsc($strEveCode) . '"'
|
|
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '" data-eve_id="' . (int)$arrRow['eve_id'] . '"'
|
|
. ' value="' . (int)$arrRow['pec_id_original'] . '">' . fxInscrGestionEsc(fxInscrGestionT('btn_annulerinscriptions')) . '</button>';
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.cancel');
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.cancel', fxInscrGestionT('btn_annulerinscriptions'));
|
|
}
|
|
if ($blnCanRestore) {
|
|
echo '<button class="btn btn-secondary btn-sm rounded-0 btn_retablir_event_promo' . $strStyleRetablir . '" type="button"'
|
|
. ' id="retablir_fiche" data-eve_code="' . fxInscrGestionEsc($strEveCode) . '"'
|
|
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '" data-eve_id="' . (int)$arrRow['eve_id'] . '"'
|
|
. ' value="' . (int)$arrRow['pec_id_original'] . '">' . fxInscrGestionEsc(fxInscrGestionT('btn_retablirinscriptions')) . '</button>';
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.restore');
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.restore', fxInscrGestionT('btn_retablirinscriptions'));
|
|
}
|
|
// RENVOI place en dernier (MSIN-4403) : retourne la confirmation au participant.
|
|
echo '<button class="btn btn-primary btn-sm rounded-0 link_confirmation" type="button"'
|
|
. ' data-no_panier="' . fxInscrGestionEsc($arrRow['no_panier']) . '"'
|
|
. ' data-no_commande="' . fxInscrGestionEsc($arrRow['no_commande']) . '"'
|
|
. ' data-lng="' . $strLangue . '">' . fxInscrGestionEsc($strRenvoi) . '</button>';
|
|
echo '</div>';
|
|
if ($blnCanRefund) {
|
|
// Panneau de remboursement : vide au depart, rempli en AJAX a la 1ere ouverture (action=refund_form).
|
|
// data-loaded evite de recharger inutilement ; data-no_panier identifie la commande cote serveur.
|
|
// Place AVANT le panneau transaction pour qu'a l'ouverture le formulaire apparaisse au-dessus du detail.
|
|
echo '<div class="inscr-gestion-refund-panel" id="inscr-gestion-refund-panel" style="margin-top:10px;"'
|
|
. ' data-no_panier="' . fxInscrGestionEsc($arrRow['no_panier']) . '"'
|
|
. ' data-loaded="0" hidden></div>';
|
|
}
|
|
// Panneau de transaction : vide au depart, rempli en AJAX a la 1ere ouverture (action=transaction_resume).
|
|
// Sous les boutons, repliable, accessible a tout moment (independant du remboursement).
|
|
echo '<div class="inscr-gestion-transaction-panel" id="inscr-gestion-transaction-panel" style="margin-top:10px;"'
|
|
. ' data-no_panier="' . fxInscrGestionEsc($arrRow['no_panier']) . '"'
|
|
. ' data-loaded="0" hidden></div>';
|
|
fxInscrGestionRenderFicheSectionEnd();
|
|
}
|
|
|
|
if ($blnHasEditable || $blnInspect) {
|
|
fxInscrGestionRenderFicheSectionStart('editable', fxInscrGestionT('inscr_gestion_section_editable'), 'fa-pencil-square-o', true);
|
|
|
|
if ($blnCanBib) {
|
|
$strFullBibInputId = $strBibInputId . $intParId;
|
|
// Scanner OCR toujours offert sur la fiche de gestion : la saisie se fait
|
|
// souvent au cellulaire / a une table d'inscription. La lecture est 100%
|
|
// cote client (Tesseract.js) et ne touche aucun endpoint serveur protege.
|
|
$blnCanBibScan = true;
|
|
echo '<div class="inscr-gestion-field-block" data-inscr-field="bib">';
|
|
echo '<div class="inscr-gestion-field-block__label">' . fxInscrGestionEsc(fxInscrGestionT('promoteur_bib_number')) . '</div>';
|
|
if ($blnCanBibScan) {
|
|
fxInscrGestionRenderBibScanBlock($strFullBibInputId, $strLangue);
|
|
}
|
|
echo '<div class="inscr-gestion-bib-row">';
|
|
echo '<input class="form-control rounded-0" type="text" id="' . $strFullBibInputId . '" value="' . fxInscrGestionEsc($strBib) . '">';
|
|
if ($blnCanBibScan) {
|
|
echo '<button class="btn btn-secondary rounded-0 inscr-gestion-bib-scan-toggle" type="button" aria-expanded="false"'
|
|
. ' title="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_btn')) . '"'
|
|
. ' aria-label="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_bib_scan_btn')) . '">';
|
|
echo '<i class="fa fa-camera" aria-hidden="true"></i>';
|
|
echo '</button>';
|
|
}
|
|
echo '<button class="btn btn-primary rounded-0 btn_bib" type="button" data-action="' . $strBibAction . '"'
|
|
. ' data-eve_id="' . rawurlencode(base64_encode((string)$arrRow['eve_id'])) . '"'
|
|
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '"'
|
|
. ' data-par_id="' . (int)$intParId . '"'
|
|
. ' data-pec_id="' . (int)$arrRow['pec_id_original'] . '">OK</button>';
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.bib_edit');
|
|
echo '</div>';
|
|
echo '</div>';
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.bib_edit', fxInscrGestionT('promoteur_bib_number'));
|
|
}
|
|
|
|
if ($blnCanStatut) {
|
|
echo '<div class="inscr-gestion-field-block inscr-gestion-field-block--statut" data-inscr-field="statut">';
|
|
echo '<div class="inscr-gestion-field-block__label">' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_label')) . '</div>';
|
|
fxInscrGestionRenderStatutField($intParId, $arrRow['par_statut_course'] ?? '', $arrRow['eve_id'], $strLangue);
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.statut_edit');
|
|
echo '</div>';
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.statut_edit', fxInscrGestionT('inscr_gestion_statut_label'));
|
|
}
|
|
|
|
$strRemisDate = trim((string)$arrRow['no_bib_remis_date']);
|
|
if ($strRemisDate === '0000-00-00 00:00:00') {
|
|
$strRemisDate = '';
|
|
}
|
|
$strRemisPar = trim((string)$arrRow['no_bib_remis_par']);
|
|
|
|
if ($blnCanRemis) {
|
|
echo '<div class="inscr-gestion-field-block" data-inscr-field="remis">';
|
|
echo '<div class="inscr-gestion-remis-row">';
|
|
echo '<div class="inscr-gestion-remis-row__left">';
|
|
echo '<div class="inscr-gestion-field-block__label inscr-gestion-field-block__label--inline">' . fxInscrGestionEsc(fxInscrGestionT('promoteur_bib_enregistre')) . '</div>';
|
|
echo '<span id="' . (int)$intParId . '">';
|
|
echo '<a class="btn btn-sm rounded-0 btn_remis ' . $strRemisClass . '" href="#" data-action="remis"'
|
|
. ' data-table="' . rawurlencode(base64_encode('resultats_participants')) . '"'
|
|
. ' data-field="no_bib_remis" data-key="par_id" data-valeur="' . $intRemisVal . '"'
|
|
. ' data-id="' . (int)$intParId . '">' . $strRemisIcon . '</a>';
|
|
echo '</span>';
|
|
echo '</div>';
|
|
echo '<div class="inscr-gestion-remis-row__meta inscr-gestion-muted">';
|
|
echo '<span id="date_' . (int)$intParId . '">' . fxInscrGestionEsc($strRemisDate) . '</span>';
|
|
if ($strRemisDate !== '' && $strRemisPar !== '') {
|
|
echo '<span class="inscr-gestion-remis-row__sep"> — </span>';
|
|
}
|
|
echo '<span id="par_' . (int)$intParId . '">' . fxInscrGestionEsc($strRemisPar) . '</span>';
|
|
echo '</div></div></div>';
|
|
fxInscrGestionPermInspectEcho('inscriptions_gestion.bib_remis');
|
|
} elseif ($blnInspect) {
|
|
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.bib_remis', fxInscrGestionT('promoteur_bib_enregistre'));
|
|
}
|
|
|
|
fxInscrGestionRenderFicheSectionEnd();
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
function fxInscrGestionRun($intEveId, $strLangue) {
|
|
$strBaseUrl = fxInscrGestionBaseUrl($strLangue);
|
|
$arrReq = fxInscrGestionParseRequest();
|
|
|
|
if ($arrReq['pec_id'] > 0) {
|
|
$arrRow = fxInscrGestionFetchRowByPec($arrReq['pec_id'], $intEveId);
|
|
if ($arrRow === null) {
|
|
echo '<div class="alert alert-danger">' . fxInscrGestionEsc(fxInscrGestionT('txt_recherche_no_result')) . '</div>';
|
|
echo '<a class="btn btn-primary rounded-0" href="' . fxInscrGestionEsc(fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null))) . '">';
|
|
echo fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_back_list')) . '</a>';
|
|
return;
|
|
}
|
|
fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq, $arrRow);
|
|
return;
|
|
}
|
|
|
|
fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq);
|
|
}
|