diff --git a/ajax_bib_range.php b/ajax_bib_range.php index af204f6..b63389a 100644 --- a/ajax_bib_range.php +++ b/ajax_bib_range.php @@ -43,6 +43,7 @@ $arrBibAjaxActions = [ 'batch_global_analysis', 'batch_global_simulate', 'global_batch_panel', + 'dist_print_panel', ]; if ($action !== '' && in_array($action, $arrBibAjaxActions, true)) { @@ -1153,6 +1154,29 @@ if ($action == 'qty_summary') { exit; } +// MSIN-4433 — Panneau impression PDF distribution dossards +if ($action == 'dist_print_panel') { + + $int_eve_id = (int)($_POST['eve_id'] ?? $_GET['eve_id'] ?? 0); + + if ($int_eve_id <= 0) { + echo json_encode([ + 'success' => false, + 'message' => fxBibMsg('bib_v4_ajax_epr_invalid') + ]); + exit; + } + + $tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue); + + echo json_encode([ + 'success' => true, + 'html' => renderBibDistPrintPanel($int_eve_id, $strLangue, $tabPanel), + 'meta' => $tabPanel['meta'] ?? [], + ]); + exit; +} + // ===================== // ACTION INVALIDE // ===================== diff --git a/bib_dist_print.php b/bib_dist_print.php new file mode 100644 index 0000000..fa4a876 --- /dev/null +++ b/bib_dist_print.php @@ -0,0 +1,46 @@ + intMax) { + cb.checked = false; + } + }); + + let form = panel.querySelector('.bib-dist-print-form'); + if (form) { + form.addEventListener('submit', function () { + window.setTimeout(function () { + refreshBibDistPrintPanel(); + }, 1500); + }); + } + } + /** MSIN-4424 — Rafraîchit le sommaire des quantités (si déjà chargé ou ouverture). */ function refreshBibQtySummaryPanel() { let mount = document.getElementById('bib-qty-summary-mount'); diff --git a/php/inc_fx_promoteur.php b/php/inc_fx_promoteur.php index 713cc07..926807d 100644 --- a/php/inc_fx_promoteur.php +++ b/php/inc_fx_promoteur.php @@ -3343,6 +3343,19 @@ function fxBibStaticFallback($clef) { 'bib_v4_qty_summary_by_epr' => ['fr' => 'Détail par épreuve', 'en' => 'Breakdown by race'], 'bib_v4_qty_summary_col_epr' => ['fr' => 'Épreuve', 'en' => 'Race'], 'bib_v4_ajax_global_sim_summary' => ['fr' => '%d épreuve(s) · %d dispo / %d à assigner → %d assignables (%d manque)', 'en' => '%d race(s) · %d avail. / %d to assign → %d assignable (%d short)'], + 'bib_v4_dist_print_title' => ['fr' => 'Impression PDF — distribution des dossards', 'en' => 'PDF print — bib distribution'], + 'bib_v4_dist_print_questions' => ['fr' => 'Colonnes optionnelles (questions)', 'en' => 'Optional columns (questions)'], + 'bib_v4_dist_print_generate' => ['fr' => 'Générer le PDF', 'en' => 'Generate PDF'], + 'bib_v4_dist_print_last_none' => ['fr' => 'Aucune impression enregistrée pour cet événement.', 'en' => 'No print recorded for this event yet.'], + 'bib_v4_dist_print_max_questions' => ['fr' => 'Maximum %d questions par épreuve pour le format lettre.', 'en' => 'Maximum %d questions per race for letter format.'], + 'bib_v4_dist_print_no_questions' => ['fr' => 'Aucune question éligible pour cette épreuve.', 'en' => 'No eligible question for this race.'], + 'bib_v4_dist_print_col_bib' => ['fr' => 'Dossard', 'en' => 'Bib'], + 'bib_v4_dist_print_col_nom' => ['fr' => 'Nom', 'en' => 'Last name'], + 'bib_v4_dist_print_col_prenom' => ['fr' => 'Prénom', 'en' => 'First name'], + 'bib_v4_dist_print_col_sexe' => ['fr' => 'Sexe', 'en' => 'Gender'], + 'bib_v4_dist_print_empty_epr' => ['fr' => 'Aucun dossard assigné pour cette épreuve.', 'en' => 'No bib assigned for this race.'], + 'bib_v4_dist_print_last' => ['fr' => 'Dernière impression : %s — %s', 'en' => 'Last print: %s — %s'], + 'bib_v4_dist_print_footer' => ['fr' => 'Imprimé le %s — %s', 'en' => 'Printed on %s — %s'], ]; return $tab[$clef][$lng] ?? ''; @@ -4609,6 +4622,10 @@ function fxShowBibTool4($str_code, $int_eve_id, $strLangue){ +
+ +
+ @@ -7723,4 +7740,744 @@ function fxResolveTeamBib( } return null; +} + +// ============================================================================= +// MSIN-4433 — Impression PDF distribution des dossards +// ============================================================================= + +/** MSIN-4433 — Limite de colonnes questions (format lettre 8½ × 11). */ +function fxBibDistPrintMaxQuestions() { + return 5; +} + +/** MSIN-4433 — Nom affiché du compte connecté (promoteur ou superadmin). */ +function fxBibGetCurrentPromoteurDisplayName() { + if (!empty($_SESSION['usa_id']) && !empty($_SESSION['usa_info']) && is_array($_SESSION['usa_info'])) { + $str = trim((string)($_SESSION['usa_info']['com_prenom'] ?? '') . ' ' . (string)($_SESSION['usa_info']['com_nom'] ?? '')); + if ($str !== '') { + return $str; + } + } + if (!empty($_SESSION['com_info']) && is_array($_SESSION['com_info'])) { + $str = trim((string)($_SESSION['com_info']['com_prenom'] ?? '') . ' ' . (string)($_SESSION['com_info']['com_nom'] ?? '')); + if ($str !== '') { + return $str; + } + } + return trim((string)($_SESSION['com_prenom'] ?? '') . ' ' . (string)($_SESSION['com_nom'] ?? '')); +} + +/** MSIN-4433 — Accès génération PDF (session, permissions, CSRF). */ +function fxBibRequireDistPrintAccess() { + if (!fxBibRequirePromoteurSession()) { + http_response_code(403); + header('Content-Type: text/plain; charset=utf-8'); + echo fxBibMsg('bib_v4_ajax_session_invalid'); + exit; + } + + if (empty($_SESSION['usa_id'])) { + require_once __DIR__ . '/inc_fx_eve_acces.php'; + $intComId = (int)($_SESSION['com_id'] ?? 0); + $intEveId = (int)($_REQUEST['eve_id'] ?? $_POST['eve_id'] ?? 0); + + if ($intComId <= 0 || $intEveId <= 0 + || !fxEveAccesHasAnyPermission($intComId, $intEveId, array('dossards.manage', 'epreuves.edit_qte'))) { + http_response_code(403); + header('Content-Type: text/plain; charset=utf-8'); + echo fxBibMsg('bib_v4_ajax_unauthorized'); + exit; + } + } + + $strToken = $_POST['csrf_token'] ?? $_REQUEST['csrf_token'] ?? ''; + if (!fxBibValidateCsrf($strToken)) { + http_response_code(403); + header('Content-Type: text/plain; charset=utf-8'); + echo fxBibMsg('bib_v4_ajax_unauthorized'); + exit; + } +} + +/** MSIN-4433 — Parse liste d'IDs questions depuis chaîne CSV. */ +function fxBibParseDistPrintQueIds($strCsv) { + if ($strCsv === null || $strCsv === '') { + return []; + } + $out = []; + foreach (explode(',', (string)$strCsv) as $part) { + $intId = (int)trim($part); + if ($intId > 0 && !in_array($intId, $out, true)) { + $out[] = $intId; + } + } + return $out; +} + +/** MSIN-4433 — Sérialise les IDs questions pour stockage. */ +function fxBibDistPrintQueIdsToCsv(array $tabQueIds) { + $out = []; + foreach ($tabQueIds as $mixId) { + $intId = (int)$mixId; + if ($intId > 0 && !in_array($intId, $out, true)) { + $out[] = $intId; + } + } + return implode(',', $out); +} + +/** MSIN-4433 — Libellé court sexe pour le PDF. */ +function fxBibDistPrintSexeLabel($strSexe, $strLangue = 'fr') { + $strSexe = strtolower(trim((string)$strSexe)); + if ($strLangue === 'en') { + $tab = ['f' => 'F', 'h' => 'M', 'n' => 'X', 'a' => 'O']; + } else { + $tab = ['f' => 'F', 'h' => 'H', 'n' => 'X', 'a' => 'A']; + } + return $tab[$strSexe] ?? strtoupper($strSexe); +} + +/** MSIN-4433 — Date/heure affichée (pied de page, panneau). */ +function fxBibFormatDistPrintDateTime($strWhen = '', $strLangue = 'fr') { + $ts = ($strWhen !== '') ? strtotime($strWhen) : time(); + if ($ts === false) { + $ts = time(); + } + if ($strLangue === 'en') { + return date('F j, Y, g:i a', $ts); + } + $tabMonths = [ + 1 => 'janvier', 2 => 'février', 3 => 'mars', 4 => 'avril', + 5 => 'mai', 6 => 'juin', 7 => 'juillet', 8 => 'août', + 9 => 'septembre', 10 => 'octobre', 11 => 'novembre', 12 => 'décembre', + ]; + $intDay = (int)date('j', $ts); + $intMonth = (int)date('n', $ts); + $intYear = (int)date('Y', $ts); + $strTime = date('H:i', $ts); + return $intDay . ' ' . ($tabMonths[$intMonth] ?? '') . ' ' . $intYear . ', ' . $strTime; +} + +/** MSIN-4433 — Métadonnées dernière impression (événement). */ +function fxBibGetDistPrintMeta($int_eve_id) { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + if ($int_eve_id <= 0) { + return ['at' => '', 'by' => '', 'com_id' => 0]; + } + + $row = $objDatabase->fxGetRow(" + SELECT eve_bib_dist_print_at, eve_bib_dist_print_by, eve_bib_dist_print_com_id + FROM inscriptions_evenements + WHERE eve_id = $int_eve_id + LIMIT 1 + "); + + if (!is_array($row)) { + return ['at' => '', 'by' => '', 'com_id' => 0]; + } + + return [ + 'at' => trim((string)($row['eve_bib_dist_print_at'] ?? '')), + 'by' => trim((string)($row['eve_bib_dist_print_by'] ?? '')), + 'com_id' => (int)($row['eve_bib_dist_print_com_id'] ?? 0), + ]; +} + +/** MSIN-4433 — Persiste date / auteur de l'impression. */ +function fxBibSaveDistPrintMeta($int_eve_id, $int_com_id, $str_by) { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + $int_com_id = (int)$int_com_id; + $str_by = trim((string)$str_by); + if ($int_eve_id <= 0) { + return; + } + + $sql = " + UPDATE inscriptions_evenements + SET eve_bib_dist_print_at = '" . $objDatabase->fxEscape(fxGetDateTime()) . "', + eve_bib_dist_print_by = '" . $objDatabase->fxEscape($str_by) . "', + eve_bib_dist_print_com_id = $int_com_id + WHERE eve_id = $int_eve_id + LIMIT 1 + "; + $objDatabase->fxQuery($sql); +} + +/** + * MSIN-4433 — Données panneau : épreuves, questions éligibles, sélection mémorisée. + * @return array{meta: array, epreuves: array>} + */ +function fxBibCollectDistPrintPanelData($int_eve_id, $strLangue = 'fr') { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + $tabOut = ['meta' => fxBibGetDistPrintMeta($int_eve_id), 'epreuves' => []]; + + if ($int_eve_id <= 0) { + return $tabOut; + } + + $sqlEpreuves = " + SELECT * + FROM inscriptions_epreuves + WHERE eve_id = $int_eve_id + AND epr_actif = 1 + ORDER BY epr_tri, epr_id + "; + $tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves); + if (!is_array($tabEpreuves)) { + return $tabOut; + } + + foreach ($tabEpreuves as $epr) { + $epr_id = (int)($epr['epr_id'] ?? 0); + if ($epr_id <= 0) { + continue; + } + + $tabQuestionOpts = fxBibGetQuestionSortOptions($epr_id, $int_eve_id, $strLangue); + $tabSelected = fxBibParseDistPrintQueIds($epr['ba_bib_dist_que_ids'] ?? ''); + $tabValidIds = []; + foreach ($tabQuestionOpts as $opt) { + if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { + $tabValidIds[] = (int)$m[1]; + } + } + $tabSelected = array_values(array_intersect($tabSelected, $tabValidIds)); + + $tabOut['epreuves'][] = [ + 'epr_id' => $epr_id, + 'epr_label' => fxBibAnomalyEprLabel($epr, $strLangue), + 'questions' => $tabQuestionOpts, + 'selected' => $tabSelected, + 'avec_bib' => (int)(fxInfosBibEpreuve($epr_id)['avec_bib'] ?? 0), + ]; + } + + return $tabOut; +} + +/** MSIN-4433 — Parse sélections POST dist_print[epr_id][] = que_id. */ +function fxBibParseDistPrintSelectionsFromPost(array $post) { + $tabRaw = $post['dist_print'] ?? []; + if (!is_array($tabRaw)) { + return []; + } + + $out = []; + foreach ($tabRaw as $mixEprId => $mixQueIds) { + $epr_id = (int)$mixEprId; + if ($epr_id <= 0) { + continue; + } + if (!is_array($mixQueIds)) { + $mixQueIds = [$mixQueIds]; + } + $tabIds = []; + foreach ($mixQueIds as $mixQueId) { + $intQueId = (int)$mixQueId; + if ($intQueId > 0 && !in_array($intQueId, $tabIds, true)) { + $tabIds[] = $intQueId; + } + } + $out[$epr_id] = $tabIds; + } + + return $out; +} + +/** + * MSIN-4433 — Sauvegarde les questions cochées par épreuve (à la génération PDF). + * @return array{success: bool, message?: string} + */ +function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLangue = 'fr') { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + if ($int_eve_id <= 0) { + return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')]; + } + + $intMax = fxBibDistPrintMaxQuestions(); + $tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue); + + foreach ($tabPanel['epreuves'] as $tabEpr) { + $epr_id = (int)($tabEpr['epr_id'] ?? 0); + if ($epr_id <= 0) { + continue; + } + + $tabValidIds = []; + foreach ($tabEpr['questions'] as $opt) { + if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { + $tabValidIds[] = (int)$m[1]; + } + } + + $tabChosen = $tabSelections[$epr_id] ?? []; + if (!is_array($tabChosen)) { + $tabChosen = []; + } + + $tabFiltered = []; + foreach ($tabChosen as $intQueId) { + $intQueId = (int)$intQueId; + if ($intQueId > 0 && in_array($intQueId, $tabValidIds, true) + && !in_array($intQueId, $tabFiltered, true)) { + $tabFiltered[] = $intQueId; + } + } + + if (count($tabFiltered) > $intMax) { + return [ + 'success' => false, + 'message' => fxBibMsg('bib_v4_dist_print_max_questions', $intMax), + ]; + } + + $strCsv = fxBibDistPrintQueIdsToCsv($tabFiltered); + $sql = " + UPDATE inscriptions_epreuves + SET ba_bib_dist_que_ids = '" . $objDatabase->fxEscape($strCsv) . "' + WHERE epr_id = $epr_id + AND eve_id = $int_eve_id + LIMIT 1 + "; + $objDatabase->fxQuery($sql); + } + + return ['success' => true]; +} + +/** + * MSIN-4433 — Participants avec dossard (une ligne par no_bib), tri batch. + * @return array> + */ +function fxBibGetParticipantsForDistPrint($epr_id, $sort1, $sort2 = '', $strLangue = 'fr') { + global $objDatabase; + + $epr_id = (int)$epr_id; + if ($epr_id <= 0) { + return []; + } + + $strSort1 = fxBibNormalizeSortKey($sort1); + $strSort2 = fxBibNormalizeSortKey($sort2); + if ($strSort1 === '') { + return []; + } + if ($strSort1 === $strSort2) { + $strSort2 = ''; + } + + $sqlBibNumP = fxBibSqlNoBibUnsigned('p.no_bib'); + $orderBy = fxBibBuildBatchOrderBy($epr_id, $strSort1, $strSort2, $strLangue); + + $sql = " + SELECT + p.par_id, + p.pec_id, + p.no_bib, + p.par_nom, + p.par_prenom, + p.par_sexe + FROM resultats_participants p + LEFT JOIN resultats_epreuves_commandees c + ON c.pec_id_original = p.pec_id + AND c.epr_id = p.epr_id + WHERE p.epr_id = $epr_id + AND p.is_cancelled = 0 + AND $sqlBibNumP > 0 + AND p.rol_id NOT IN (3, 4) + ORDER BY $orderBy + "; + + $rows = $objDatabase->fxGetResults($sql); + if (!is_array($rows)) { + return []; + } + + $tabSeen = []; + $tabOut = []; + foreach ($rows as $row) { + $strBibKey = (string)(int)($row['no_bib'] ?? 0); + if ($strBibKey === '0' || isset($tabSeen[$strBibKey])) { + continue; + } + $tabSeen[$strBibKey] = true; + $tabOut[] = $row; + } + + return $tabOut; +} + +/** + * MSIN-4433 — Réponses questions pour une liste de participants. + * @return array> clé "par_id:pec_id" => [que_id => réponse] + */ +function fxBibGetDistPrintQuestionAnswers($epr_id, array $tabQueIds, array $tabParticipants, $strLangue = 'fr') { + global $objDatabase; + + $epr_id = (int)$epr_id; + $tabQueIds = array_values(array_filter(array_map('intval', $tabQueIds))); + if ($epr_id <= 0 || empty($tabQueIds) || empty($tabParticipants)) { + return []; + } + + $tabParIds = []; + foreach ($tabParticipants as $row) { + $intParId = (int)($row['par_id'] ?? 0); + if ($intParId > 0) { + $tabParIds[] = $intParId; + } + } + $tabParIds = array_values(array_unique($tabParIds)); + if (empty($tabParIds)) { + return []; + } + + $strCol = ($strLangue === 'en') ? 'que_choix_en' : 'que_choix_fr'; + $strQueIds = implode(',', $tabQueIds); + $strParIds = implode(',', $tabParIds); + + $sql = " + SELECT par_id, pec_id, que_id, TRIM($strCol) AS ans + FROM resultats_questions + WHERE que_actif = 1 + AND que_id IN ($strQueIds) + AND par_id IN ($strParIds) + "; + $rows = $objDatabase->fxGetResults($sql); + if (!is_array($rows)) { + return []; + } + + $out = []; + foreach ($rows as $row) { + $strKey = (int)($row['par_id'] ?? 0) . ':' . (int)($row['pec_id'] ?? 0); + $intQueId = (int)($row['que_id'] ?? 0); + $out[$strKey][$intQueId] = trim((string)($row['ans'] ?? '')); + } + + return $out; +} + +/** MSIN-4433 — Tronque texte pour cellule PDF. */ +function fxBibDistPrintTruncate($str, $intMax = 28) { + $str = trim((string)$str); + if ($str === '') { + return ''; + } + if (function_exists('mb_strlen') && function_exists('mb_substr')) { + if (mb_strlen($str) <= $intMax) { + return $str; + } + return mb_substr($str, 0, max(1, $intMax - 1)) . '…'; + } + if (strlen($str) <= $intMax) { + return $str; + } + return substr($str, 0, max(1, $intMax - 1)) . '…'; +} + +/** MSIN-4433 — Génère et envoie le PDF (format lettre). */ +function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = '') { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + if ($int_eve_id <= 0) { + http_response_code(400); + exit; + } + + $tabEvent = $objDatabase->fxGetRow("SELECT * FROM inscriptions_evenements WHERE eve_id = $int_eve_id LIMIT 1"); + if (!is_array($tabEvent)) { + http_response_code(404); + exit; + } + + $strEventTitle = trim((string)($tabEvent['eve_nom_' . $strLangue] ?? '')); + if ($strEventTitle === '') { + $strEventTitle = trim((string)($tabEvent['eve_nom_fr'] ?? '')); + } + + $strPrintedAt = fxBibFormatDistPrintDateTime('', $strLangue); + if (trim((string)$strPrintedBy) === '') { + $strPrintedBy = fxBibGetCurrentPromoteurDisplayName(); + } + $strFooter = sprintf( + fxBibTexte('bib_v4_dist_print_footer', 0), + $strPrintedAt, + $strPrintedBy + ); + + $tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue); + + $strDocRoot = $_SERVER['DOCUMENT_ROOT'] ?? dirname(__DIR__); + require_once($strDocRoot . '/fpdf182/fpdf.php'); + + if (!class_exists('BibDistPrintPdf', false)) { + class BibDistPrintPdf extends FPDF { + public $footerText = ''; + + function Footer() { + $this->SetY(-12); + $this->SetFont('Arial', 'I', 7); + $this->Cell(0, 4, utf8_decode($this->footerText), 0, 0, 'L'); + $this->Cell(0, 4, utf8_decode('p. ' . $this->PageNo()), 0, 0, 'R'); + } + } + } + + $pdf = new BibDistPrintPdf('P', 'mm', 'letter'); + $pdf->footerText = $strFooter; + $pdf->SetMargins(10, 12, 10); + $pdf->SetAutoPageBreak(true, 14); + $pdf->AddPage(); + $pdf->SetFont('Arial', 'B', 14); + $pdf->Cell(0, 8, utf8_decode(fxBibDistPrintTruncate($strEventTitle, 80)), 0, 1, 'C'); + $pdf->SetFont('Arial', '', 10); + $pdf->Cell(0, 6, utf8_decode(fxBibTexte('bib_v4_dist_print_title', 0)), 0, 1, 'C'); + $pdf->Ln(4); + + $fltPageW = $pdf->GetPageWidth() - 20; + $fltFixedW = 18 + 42 + 42 + 12; + + foreach ($tabPanel['epreuves'] as $tabEpr) { + $epr_id = (int)($tabEpr['epr_id'] ?? 0); + if ($epr_id <= 0) { + continue; + } + + $tabEprRow = $objDatabase->fxGetRow("SELECT * FROM inscriptions_epreuves WHERE epr_id = $epr_id LIMIT 1"); + if (!is_array($tabEprRow)) { + continue; + } + + list($strSort1, $strSort2) = fxBibGetEpreuveDefaultSortKeys($tabEprRow); + $tabSelectedQue = $tabEpr['selected'] ?? []; + $tabQueCols = []; + foreach ($tabEpr['questions'] as $opt) { + if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { + $intQueId = (int)$m[1]; + if (in_array($intQueId, $tabSelectedQue, true)) { + $tabQueCols[] = [ + 'que_id' => $intQueId, + 'label' => (string)($opt['label'] ?? ('Q' . $intQueId)), + ]; + } + } + } + + $intNbQ = count($tabQueCols); + $fltQTotal = max(0, $fltPageW - $fltFixedW); + $fltQEach = ($intNbQ > 0) ? ($fltQTotal / $intNbQ) : 0; + + $pdf->SetFont('Arial', 'B', 11); + $pdf->Cell(0, 7, utf8_decode(fxBibDistPrintTruncate($tabEpr['epr_label'] ?? '', 90)), 0, 1, 'L'); + $pdf->Ln(1); + + $tabParticipants = fxBibGetParticipantsForDistPrint($epr_id, $strSort1, $strSort2, $strLangue); + if (empty($tabParticipants)) { + $pdf->SetFont('Arial', 'I', 9); + $pdf->Cell(0, 5, utf8_decode(fxBibTexte('bib_v4_dist_print_empty_epr', 0)), 0, 1, 'L'); + $pdf->Ln(3); + continue; + } + + $tabAnswers = fxBibGetDistPrintQuestionAnswers($epr_id, $tabSelectedQue, $tabParticipants, $strLangue); + + $pdf->SetFont('Arial', 'B', 8); + $pdf->SetFillColor(230, 230, 230); + $pdf->Cell(18, 6, utf8_decode(fxBibTexte('bib_v4_dist_print_col_bib', 0)), 1, 0, 'C', true); + $pdf->Cell(42, 6, utf8_decode(fxBibTexte('bib_v4_dist_print_col_nom', 0)), 1, 0, 'L', true); + $pdf->Cell(42, 6, utf8_decode(fxBibTexte('bib_v4_dist_print_col_prenom', 0)), 1, 0, 'L', true); + $pdf->Cell(12, 6, utf8_decode(fxBibTexte('bib_v4_dist_print_col_sexe', 0)), 1, 0, 'C', true); + foreach ($tabQueCols as $i => $col) { + $blnLast = ($i === $intNbQ - 1); + $pdf->Cell($fltQEach, 6, utf8_decode(fxBibDistPrintTruncate($col['label'], 22)), 1, $blnLast ? 1 : 0, 'L', true); + } + if ($intNbQ === 0) { + $pdf->Ln(); + } + + $pdf->SetFont('Arial', '', 8); + foreach ($tabParticipants as $row) { + $strKey = (int)($row['par_id'] ?? 0) . ':' . (int)($row['pec_id'] ?? 0); + $pdf->Cell(18, 5, utf8_decode((string)(int)($row['no_bib'] ?? 0)), 1, 0, 'C'); + $pdf->Cell(42, 5, utf8_decode(fxBibDistPrintTruncate($row['par_nom'] ?? '', 24)), 1, 0, 'L'); + $pdf->Cell(42, 5, utf8_decode(fxBibDistPrintTruncate($row['par_prenom'] ?? '', 24)), 1, 0, 'L'); + $pdf->Cell(12, 5, utf8_decode(fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue)), 1, 0, 'C'); + foreach ($tabQueCols as $i => $col) { + $intQueId = (int)$col['que_id']; + $strAns = $tabAnswers[$strKey][$intQueId] ?? ''; + $blnLast = ($i === $intNbQ - 1); + $pdf->Cell($fltQEach, 5, utf8_decode(fxBibDistPrintTruncate($strAns, 24)), 1, $blnLast ? 1 : 0, 'L'); + } + if ($intNbQ === 0) { + $pdf->Ln(); + } + } + + $pdf->Ln(5); + } + + $strFilename = 'distribution-dossards-' . $int_eve_id . '.pdf'; + $pdf->Output('I', $strFilename); +} + +/** MSIN-4433 — Coquille panneau impression (chargement AJAX). */ +function renderBibDistPrintPanelShell($int_eve_id, $strLangue = 'fr') { + global $vDomaine; + + $int_eve_id = (int)$int_eve_id; + $strWait = fxBibTexte('bib_v4_js_loader_wait', 0); + if ($strWait === '' || $strWait === 'bib_v4_js_loader_wait') { + $strWait = ($strLangue === 'en') ? 'Loading...' : 'Chargement...'; + } + $strRunnerSrc = $vDomaine . '/images/ms1-runner-loader.gif?v=' . _VERSION_CODE; + + ob_start(); + ?> + + + +