fxGetRow( 'SELECT com_eve_promoteur FROM inscriptions_comptes WHERE com_id = ' . intval($intComId) ); return $row !== null && trim((string)$row['com_eve_promoteur']) !== ''; } /** Utilisateur avec menu promoteur legacy (section Info promoteur). */ function fxInscrGestionUserHasPromoteurMenu($intComId) { if (fxInscrGestionUserHasLegacyPromoteurMenu($intComId)) { return true; } global $objDatabase; $row = $objDatabase->fxGetRow( 'SELECT com_rapports FROM inscriptions_comptes WHERE com_id = ' . intval($intComId) ); return $row !== null && 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 ''; echo fxEveAccesPermInspectBadge($strPermKey, 'inscr_gestion'); echo ' ' . fxInscrGestionEsc($strLabel) . ''; echo ' '; } 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 '
'; echo '
'; fxInscrGestionRenderPageHead( ($strLangue === 'fr') ? 'Inscriptions mobile' : 'Mobile registrations' ); echo ''; echo '
'; } /** 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 ''; echo '' . fxInscrGestionEsc($strLabel); echo ''; } function fxInscrGestionRenderPageHead($strTitle, $strSub = '') { echo '
'; echo '

' . fxInscrGestionEsc($strTitle) . '

'; if (trim((string)$strSub) !== '') { echo '

' . fxInscrGestionEsc($strSub) . '

'; } echo '
'; } function fxInscrGestionRenderSectionTitle($strLabel, $strIconClass) { echo '

'; echo ''; echo '' . fxInscrGestionEsc($strLabel) . ''; echo '

'; } function fxInscrGestionRenderFicheSectionStart($strModifier, $strLabel, $strIconClass, $blnOpen = true) { echo '
'; echo ''; echo ''; echo '' . fxInscrGestionEsc($strLabel) . ''; echo ''; echo '
'; } function fxInscrGestionRenderFicheSectionEnd() { echo '
'; } function fxInscrGestionRenderPanelSummary($strLabel, $strIconClass) { echo ''; echo '' . fxInscrGestionEsc($strLabel) . ''; } 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'); } /** Mode rendu fiche condensee (grille 2 colonnes dans l'onglet Details). */ function fxInscrGestionKvFicheCardMode($blnSet = null) { static $blnMode = false; if ($blnSet !== null) { $blnMode = (bool)$blnSet; } return $blnMode; } /** Valeur longue ou courriel : occupe toute la largeur de la fiche. */ function fxInscrGestionKvValueWantsFullWidth($strValue, $blnHtml = false) { if ($blnHtml) { $strPlain = trim(strip_tags((string)$strValue)); } else { $strPlain = trim((string)$strValue); } if ($strPlain === '') { return false; } $intLen = function_exists('mb_strlen') ? mb_strlen($strPlain) : strlen($strPlain); return $intLen > 48; } function fxInscrGestionRenderKvListOpen($blnFicheCard = false) { fxInscrGestionKvFicheCardMode($blnFicheCard); $strClass = 'inscr-gestion-kv-list'; if ($blnFicheCard) { $strClass .= ' inscr-gestion-fiche-card'; } echo '
'; } function fxInscrGestionRenderKvListClose() { fxInscrGestionKvFicheCardMode(false); echo '
'; } function fxInscrGestionRenderKvRow($strLabel, $strValue, $blnHtml = false, $strExtraClass = '') { if (!$blnHtml && trim((string)$strValue) === '') { return; } $strClass = 'inscr-gestion-kv-row'; if ($strExtraClass !== '') { $strClass .= ' ' . $strExtraClass; } if (fxInscrGestionKvFicheCardMode() && fxInscrGestionKvValueWantsFullWidth($strValue, $blnHtml)) { $strClass .= ' inscr-gestion-kv-row--full'; } echo '
'; echo '
' . fxInscrGestionEsc($strLabel) . '
'; echo '
'; if ($blnHtml) { echo $strValue; } else { echo fxInscrGestionEsc($strValue); } echo '
'; } 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; } if (fxInscrGestionKvFicheCardMode()) { $strClass .= ' inscr-gestion-kv-row--full'; } echo '
'; echo '' . fxInscrGestionEsc($strText) . ''; echo '
'; } 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 '
' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_label')) . '
'; return; } $strCurrent = fxInscrGestionResolveParStatutCourse($strCurrent); $strSelectId = 'inscr_statut_' . (int)$intParId; echo ''; } /** 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 '
' . fxGetPagination( fxInscrGestionPaginationUrl($strBaseUrl, $intEveId, $arrReq), $intTotal, $intPerPage, $intPage ) . '
'; } 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 '
'; fxInscrGestionRenderPageHead($strTitle); echo '
'; 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 ''; echo '' . fxInscrGestionEsc(fxUnescape($tabEv['eve_nom_' . $strLangue])) . ''; echo ''; echo ''; } echo '
'; } 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 '
'; echo ''; fxInscrGestionRenderPanelSummary(fxInscrGestionT('inscr_gestion_qr_title'), 'fa-qrcode'); echo ''; echo '
'; echo '

' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_qr_hint')) . '

'; echo ''; echo '
'; echo '
'; echo '
'; } function fxInscrGestionRenderBibScanBlock($strBibInputId, $strLangue) { echo '
'; echo '

' . fxInscrGestionEsc(fxInscrGestionScanLabel('inscr_gestion_bib_scan_hint')) . '

'; echo '
'; echo '
'; echo '
'; // Zone-cible centrale (eclaircie) : aligne le repere visuel sur la region // reellement lue par l'OCR (captureCenterFrame : ~55% largeur x 30% hauteur). echo ''; echo '' . fxInscrGestionEsc(fxInscrGestionScanLabel('inscr_gestion_bib_scan_tap')) . ''; echo '
'; echo '
'; } 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 '
'; echo ''; echo ''; echo '
'; return; } } $strBackUrl = fxInscrGestionIsEntry() ? $strBaseUrl : ($vDomaine . ($strLangue === 'fr' ? '/compte/inc_tableau_promoteur' : '/account/inc_tableau_promoteur') . '?promoteur_eve_id=' . rawurlencode(base64_encode((string)$intEveId))); echo '
'; 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 '
'; echo ''; fxInscrGestionRenderPanelSummary(fxInscrGestionT('txt_recherche'), 'fa-search'); echo ''; echo '
'; echo '
'; echo ''; $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 ''; if ($strKey === 'rech_nom_equipe') { echo '
'; fxInscrGestionRenderBibScanBlock($strKey, $strLangue); echo '
'; echo ''; echo ''; echo '
'; continue; } echo ''; } if ($arrReq['sel_rech_epreuve'] > 0) { echo ''; } if ($arrReq['chk_bib']) { echo ''; } if ($arrReq['chk_cancelled']) { echo ''; } echo '
'; echo '' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_reset_search')) . ''; echo ''; echo '
'; // 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 '
'; echo ''; fxInscrGestionRenderPanelSummary($strFilterLabel, 'fa-filter'); echo ''; echo '
'; echo '
'; echo ''; foreach (array('rech_prenom', 'rech_nom', 'rech_no_commande', 'rech_nom_equipe') as $strKey) { if ($arrReq[$strKey] !== '') { echo ''; } } echo ''; echo ''; echo ''; echo ''; echo '
'; echo '' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_reset_search')) . ''; echo ''; echo '
'; echo '
'; // Tant qu'aucune recherche n'a été lancée, on n'affiche aucune inscription : seulement une invite. if (!$blnSearchActive) { echo '
' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_search_prompt')) . '
'; echo '
'; 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 '
'; if ($strLangue === 'fr') { echo '' . (int)$intNbTotal . ' inscription' . ($intNbTotal > 1 ? 's' : '') . ''; } else { echo '' . (int)$intNbTotal . ' registration' . ($intNbTotal !== 1 ? 's' : '') . ''; } if ($intNbTotal > $intNbItemsParPage) { $intNbPages = (int)ceil($intNbTotal / $intNbItemsParPage); echo '' . ($strLangue === 'fr' ? 'Page ' : 'Page ') . $intPage . ' / ' . $intNbPages . ''; } echo '
'; if ($intNbTotal > 0) { echo '
'; // 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 ''; 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 = ' ' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_' . $strCause)) . ''; } echo ''; echo '' . fxInscrGestionEsc($strName) . $strCancelBadge . ''; echo '' . fxInscrGestionEsc($strRace) . ''; echo '' . fxInscrGestionEsc($row['no_commande']) . ''; echo ''; echo trim($strBib) !== '' ? fxInscrGestionEsc($strBib) : '—'; echo ''; echo ''; if ($row['no_bib_remis'] == 1) { echo '' . fxInscrGestionEsc(fxInscrGestionT('promoteur_bib_enregistre')) . ''; } echo ''; echo ''; echo ''; } echo '
'; echo fxInscrGestionRenderPagination($strBaseUrl, $intEveId, $arrReq, $intNbTotal, $intNbItemsParPage, $intPage); } else { echo '
' . fxInscrGestionEsc(fxInscrGestionT('txt_recherche_no_result')) . '
'; } echo '
'; } 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 = ''; $intRemisVal = 0; } else { $strRemisClass = 'btn-primary'; $strRemisIcon = ''; $intRemisVal = 1; } echo '
'; fxInscrGestionRenderNavBack($strListUrl, fxInscrGestionT('inscr_gestion_back_list')); echo '
'; echo '

' . fxInscrGestionEsc(fxUnescape($arrRow['par_nom']) . ', ' . fxUnescape($arrRow['par_prenom'])) . '

'; echo '
'; $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(true); 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'), '' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_' . $strCause)) . '', 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) { // MSIN — a l'ouverture de la fiche, seul l'onglet Détails reste deploye. fxInscrGestionRenderFicheSectionStart('gestion', fxInscrGestionT('inscr_gestion_section_management'), 'fa-cog', false); echo '
'; // Libelle devant le bouton facture (numero de commande) — invite a afficher la facture. echo '' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_show_invoice')) . ''; echo '' . fxInscrGestionEsc($arrRow['no_commande']) . ''; // 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 ''; if ($blnCanEdit) { echo ''; 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 ''; fxInscrGestionPermInspectEcho('inscriptions_gestion.refund'); } elseif ($blnInspect) { fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.refund', fxInscrGestionT('inscr_gestion_remboursement')); } if ($blnCanCancel) { echo ''; fxInscrGestionPermInspectEcho('inscriptions_gestion.cancel'); } elseif ($blnInspect) { fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.cancel', fxInscrGestionT('btn_annulerinscriptions')); } if ($blnCanRestore) { echo ''; 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 ''; echo '
'; 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 ''; } // 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 ''; fxInscrGestionRenderFicheSectionEnd(); } if ($blnHasEditable || $blnInspect) { // MSIN — champs modifiables fermes par defaut ; ouverts si arrivee par scan QR (dossard). fxInscrGestionRenderFicheSectionStart('editable', fxInscrGestionT('inscr_gestion_section_editable'), 'fa-pencil-square-o', $blnFromQr); 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 '
'; echo '
' . fxInscrGestionEsc(fxInscrGestionT('promoteur_bib_number')) . '
'; if ($blnCanBibScan) { fxInscrGestionRenderBibScanBlock($strFullBibInputId, $strLangue); } echo '
'; echo ''; if ($blnCanBibScan) { echo ''; } echo ''; fxInscrGestionPermInspectEcho('inscriptions_gestion.bib_edit'); echo '
'; echo '
'; } elseif ($blnInspect) { fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.bib_edit', fxInscrGestionT('promoteur_bib_number')); } if ($blnCanStatut) { echo '
'; echo '
' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_label')) . '
'; fxInscrGestionRenderStatutField($intParId, $arrRow['par_statut_course'] ?? '', $arrRow['eve_id'], $strLangue); fxInscrGestionPermInspectEcho('inscriptions_gestion.statut_edit'); echo '
'; } 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 '
'; echo '
'; echo '
'; echo '
' . fxInscrGestionEsc(fxInscrGestionT('promoteur_bib_enregistre')) . '
'; echo ''; echo '' . $strRemisIcon . ''; echo ''; echo '
'; echo '
'; echo '' . fxInscrGestionEsc($strRemisDate) . ''; if ($strRemisDate !== '' && $strRemisPar !== '') { echo ''; } echo '' . fxInscrGestionEsc($strRemisPar) . ''; echo '
'; fxInscrGestionPermInspectEcho('inscriptions_gestion.bib_remis'); } elseif ($blnInspect) { fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.bib_remis', fxInscrGestionT('promoteur_bib_enregistre')); } fxInscrGestionRenderFicheSectionEnd(); } echo '
'; } function fxInscrGestionRun($intEveId, $strLangue) { $strBaseUrl = fxInscrGestionBaseUrl($strLangue); $arrReq = fxInscrGestionParseRequest(); if ($arrReq['pec_id'] > 0) { $arrRow = fxInscrGestionFetchRowByPec($arrReq['pec_id'], $intEveId); if ($arrRow === null) { echo '
' . fxInscrGestionEsc(fxInscrGestionT('txt_recherche_no_result')) . '
'; echo ''; echo fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_back_list')) . ''; return; } fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq, $arrRow); return; } fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq); }