MSIN-4471 — Enhance bib distribution document handling by adding new columns for participant names and checkboxes. Adjust maximum question display for improved readability. Update version code and documentation content for clarity and usability. Increment version code to 4.72.861.

This commit is contained in:
2026-07-22 07:43:03 -04:00
parent 9233c65351
commit 2d706fb628
4 changed files with 127 additions and 52 deletions

View File

@ -3706,6 +3706,9 @@ function fxBibStaticFallback($clef) {
'bib_v4_dist_print_col_bib' => ['fr' => 'Dossard', 'en' => 'Bib'],
'bib_v4_dist_print_col_nom' => ['fr' => 'Nom', 'en' => 'Last name'],
'bib_v4_dist_print_col_prenom' => ['fr' => 'Prénom', 'en' => 'First name'],
// MSIN-4471 — Feuille bénévole : nom+prénom + case remise.
'bib_v4_dist_print_col_nom_prenom' => ['fr' => 'Nom, Prénom', 'en' => 'Last name, First name'],
'bib_v4_dist_print_col_check' => ['fr' => '', 'en' => ''],
'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'],
@ -9049,9 +9052,9 @@ function fxResolveTeamBib(
// MSIN-4433 — Impression PDF distribution des dossards
// =============================================================================
/** MSIN-4433 — Limite de colonnes questions (format lettre 8½ × 11). */
/** MSIN-4433 / MSIN-4471 — Limite de colonnes questions (feuille bénévole lettre). */
function fxBibDistPrintMaxQuestions() {
return 5;
return 3;
}
/** MSIN-4433 — Nom affiché du compte connecté (promoteur ou superadmin). */
@ -9323,10 +9326,8 @@ function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLan
}
if (count($tabFiltered) > $intMax) {
return [
'success' => false,
'message' => fxBibMsg('bib_v4_dist_print_max_questions', $intMax),
];
// MSIN-4471 — Max abaissé à 3 : garder les N premières plutôt que bloquer.
$tabFiltered = array_slice($tabFiltered, 0, $intMax);
}
$strCsv = fxBibDistPrintQueIdsToCsv($tabFiltered);
@ -9344,7 +9345,9 @@ function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLan
}
/**
* MSIN-4433 — Participants avec dossard (une ligne par no_bib), tri batch.
* MSIN-4433 / MSIN-4471 — Participants avec dossard (une ligne par no_bib).
* Tri fixe nom + prénom : les bénévoles cherchent par nom à la table.
* ($sort1 / $sort2 conservés pour compat signature ; ignorés.)
* @return array<int, array<string, mixed>>
*/
function fxBibGetParticipantsForDistPrint($epr_id, $sort1, $sort2 = '', $strLangue = 'fr') {
@ -9355,17 +9358,9 @@ function fxBibGetParticipantsForDistPrint($epr_id, $sort1, $sort2 = '', $strLang
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);
// MSIN-4471 — Toujours alphabétique nom / prénom (pas le tri batch d'assignation).
$orderBy = 'TRIM(p.par_nom), TRIM(p.par_prenom), p.par_id ASC';
$sql = "
SELECT
@ -9886,8 +9881,15 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy =
// MSIN-4471 — Pages d'explication (doc) avant les tableaux d'épreuves.
fxBibOutputDistPrintIntroPages($pdf, $int_eve_id, $strLangue);
// MSIN-4471 — Feuille bénévole : case remise + dossard gros + nom/prénom + ~2025 lignes/page.
$fltPageW = $pdf->GetPageWidth() - 20;
$fltFixedW = 18 + 42 + 42 + 12;
$fltColCheck = 9;
$fltColBib = 28;
$fltColSexe = 12;
$fltFixedW = $fltColCheck + $fltColBib + $fltColSexe;
$fltRowH = 8;
$fltHeadH = 8;
$fltBottom = method_exists($pdf, 'GetBreakMargin') ? $pdf->GetBreakMargin() : 14;
$blnHasPrintedEpreuve = false;
foreach ($tabPanel['epreuves'] as $tabEpr) {
@ -9901,8 +9903,8 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy =
continue;
}
list($strSort1, $strSort2) = fxBibGetEpreuveDefaultSortKeys($tabEprRow);
$tabParticipants = fxBibGetParticipantsForDistPrint($epr_id, $strSort1, $strSort2, $strLangue);
// MSIN-4471 — Tri nom/prénom forcé dans fxBibGetParticipantsForDistPrint (args ignorés).
$tabParticipants = fxBibGetParticipantsForDistPrint($epr_id, 'ba:2', '', $strLangue);
// MSIN-4433 — Épreuve sans dossard assigné : ne pas imprimer la section.
if (empty($tabParticipants)) {
continue;
@ -9921,51 +9923,93 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy =
}
}
}
// MSIN-4471 — Max 3 questions affichées (lisibilité feuille bénévole).
if (count($tabQueCols) > fxBibDistPrintMaxQuestions()) {
$tabQueCols = array_slice($tabQueCols, 0, fxBibDistPrintMaxQuestions());
}
$intNbQ = count($tabQueCols);
$fltQTotal = max(0, $fltPageW - $fltFixedW);
$fltQEach = ($intNbQ > 0) ? ($fltQTotal / $intNbQ) : 0;
$fltNameW = 78;
$fltQTotal = max(0, $fltPageW - $fltFixedW - $fltNameW);
if ($intNbQ === 0) {
$fltNameW = $fltPageW - $fltFixedW;
$fltQEach = 0;
} else {
$fltQEach = $fltQTotal / $intNbQ;
}
// MSIN-4470 — Chaque épreuve commence sur une page neuve; Header répète les titres.
$pdf->eprTitle = fxBibDistPrintTruncate($tabEpr['epr_label'] ?? '', 90);
$pdf->AddPage();
$blnHasPrintedEpreuve = true;
$tabAnswers = fxBibGetDistPrintQuestionAnswers($epr_id, $tabSelectedQue, $tabParticipants, $strLangue);
$pdf->SetFont('Arial', 'B', 8);
$pdf->SetFillColor(230, 230, 230);
$pdf->Cell(18, 6, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_bib', 0)), 1, 0, 'C', true);
$pdf->Cell(42, 6, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_nom', 0)), 1, 0, 'L', true);
$pdf->Cell(42, 6, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_prenom', 0)), 1, 0, 'L', true);
$pdf->Cell(12, 6, fxBibDistPrintPdfText(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, fxBibDistPrintPdfText(fxBibDistPrintTruncate($col['label'], 22)), 1, $blnLast ? 1 : 0, 'L', true);
}
if ($intNbQ === 0) {
$pdf->Ln();
}
$fnDrawTableHeader = function () use ($pdf, $fltColCheck, $fltColBib, $fltNameW, $fltColSexe, $fltQEach, $tabQueCols, $intNbQ, $fltHeadH) {
$pdf->SetFont('Arial', 'B', 10);
$pdf->SetFillColor(220, 220, 220);
$pdf->Cell($fltColCheck, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_check', 0)), 1, 0, 'C', true);
$pdf->Cell($fltColBib, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_bib', 0)), 1, 0, 'C', true);
$pdf->Cell($fltNameW, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_nom_prenom', 0)), 1, 0, 'L', true);
$pdf->Cell($fltColSexe, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_sexe', 0)), 1, $intNbQ === 0 ? 1 : 0, 'C', true);
foreach ($tabQueCols as $i => $col) {
$blnLast = ($i === $intNbQ - 1);
$pdf->Cell($fltQEach, $fltHeadH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($col['label'], 18)), 1, $blnLast ? 1 : 0, 'L', true);
}
};
$pdf->SetFont('Arial', '', 8);
$fnDrawTableHeader();
$intRow = 0;
foreach ($tabParticipants as $row) {
// Nouvelle page + répéter l'en-tête de colonnes (feuille bénévole).
if ($pdf->GetY() + $fltRowH > $pdf->GetPageHeight() - $fltBottom) {
$pdf->AddPage();
$fnDrawTableHeader();
}
$strKey = fxBibDistPrintAnswerKey($row);
$pdf->Cell(18, 5, fxBibDistPrintPdfText((string)(int)($row['no_bib'] ?? 0)), 1, 0, 'C');
$pdf->Cell(42, 5, fxBibDistPrintPdfText(fxBibDistPrintTruncate($row['par_nom'] ?? '', 24)), 1, 0, 'L');
$pdf->Cell(42, 5, fxBibDistPrintPdfText(fxBibDistPrintTruncate($row['par_prenom'] ?? '', 24)), 1, 0, 'L');
$pdf->Cell(12, 5, fxBibDistPrintPdfText(fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue)), 1, 0, 'C');
$strNom = trim((string)($row['par_nom'] ?? ''));
$strPrenom = trim((string)($row['par_prenom'] ?? ''));
$strNomPrenom = $strNom;
if ($strPrenom !== '') {
$strNomPrenom .= ($strNom !== '' ? ', ' : '') . $strPrenom;
}
$blnAlt = ($intRow % 2) === 1;
if ($blnAlt) {
$pdf->SetFillColor(245, 245, 245);
} else {
$pdf->SetFillColor(255, 255, 255);
}
$blnFill = true;
// Case à cocher (vide) pour marquer la remise.
$pdf->SetFont('Arial', '', 11);
$pdf->Cell($fltColCheck, $fltRowH, '', 1, 0, 'C', $blnFill);
// Dossard — signal principal.
$pdf->SetFont('Arial', 'B', 14);
$pdf->Cell($fltColBib, $fltRowH, fxBibDistPrintPdfText((string)(int)($row['no_bib'] ?? 0)), 1, 0, 'C', $blnFill);
// Nom, Prénom.
$pdf->SetFont('Arial', '', 11);
$pdf->Cell($fltNameW, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strNomPrenom, 42)), 1, 0, 'L', $blnFill);
$pdf->SetFont('Arial', '', 11);
$pdf->Cell($fltColSexe, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue)), 1, $intNbQ === 0 ? 1 : 0, 'C', $blnFill);
foreach ($tabQueCols as $i => $col) {
$intQueId = (int)$col['que_id'];
$strAns = $tabAnswers[$strKey][$intQueId] ?? '';
$blnLast = ($i === $intNbQ - 1);
$pdf->Cell($fltQEach, 5, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strAns, 24)), 1, $blnLast ? 1 : 0, 'L');
}
if ($intNbQ === 0) {
$pdf->Ln();
$pdf->SetFont('Arial', '', 10);
$pdf->Cell($fltQEach, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strAns, 20)), 1, $blnLast ? 1 : 0, 'L', $blnFill);
}
$intRow++;
}
$pdf->Ln(5);
$pdf->Ln(4);
}
if (!$blnHasPrintedEpreuve && $pdf->PageNo() < 1) {

View File

@ -7,8 +7,8 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.860'); // MSIN-4470
define('_DATE_CODE', '2026-07-21');
define('_VERSION_CODE', '4.72.861'); // MSIN-4471
define('_DATE_CODE', '2026-07-22');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');

View File

@ -19,8 +19,8 @@ VALUES ('bib_v4_dist_print_doc', 'bib_dist_print', 'compte.php', 1, NOW());
-- FR
-- ---------------------------------------------------------------------------
INSERT INTO `doc_page` (`doc_mod_clef`, `doc_page_clef`, `doc_langue`, `doc_titre`, `doc_sous_titre`, `doc_html`, `doc_prg`, `doc_tri`, `doc_actif`, `doc_creation`) VALUES
('bib_dist_print', 'bib_dist_print_reco', 'fr', 'Recommandations — distribution des dossards', 'À lire avant de commencer',
'<article class="ms1-doc-article"><p><strong>Texte provisoire (MSIN-4471)</strong> — Remplacez ce contenu via l''éditeur de documentation.</p><h3>Règles de base</h3><ol><li>Vérifiez l''identité du participant avant de remettre le dossard.</li><li>Cochez ou rayez le numéro sur la liste imprimée après chaque remise.</li><li>Gardez les dossards non remis dans un bac séparé clairement étiqueté.</li></ol><h3>Organisation de la table</h3><ul><li>Une personne pour la liste, une pour les dossards.</li><li>Préparez les épreuves dans l''ordre d''arrivée des files.</li></ul><blockquote>Astuce images : déposez vos fichiers dans <strong>images/doc/</strong> puis utilisez &lt;img src="/images/doc/nom-fichier.png"&gt;.</blockquote></article>',
('bib_dist_print', 'bib_dist_print_reco', 'fr', 'Conseils à la distribution', 'Pour une remise de dossards sans erreur',
'<article class="ms1-doc-article"><p><em>À lire avant de commencer.</em> Quelques secondes à chaque remise évitent les échanges, les erreurs de chronométrage et les résultats incorrects.</p><h3>1. Familles et groupes — plusieurs dossards</h3><p>Lorsque vous remettez plusieurs dossards à une même famille ou à un groupe, assurez-vous que le prénom figure sur chaque dossard. S''il n''y est pas déjà, <strong>écrivez-le au verso</strong>. Ainsi, chacun part avec le bon numéro : un échange entre proches fausse le chronométrage et les résultats.</p><h3>2. Ne pas céder son dossard</h3><p>Un dossard inscrit à un nom <strong>ne doit pas</strong> être remis à une autre personne. Si un échange a déjà eu lieu, <strong>avisez immédiatement les organisateurs</strong> afin qu''ils corrigent la base de données avant la course.</p><h3>3. Dossard bien visible à l''avant</h3><p>Rappelez au participant d''épingler son dossard <strong>bien visible à l''avant du torse</strong>. C''est essentiel pour un chronométrage fiable et un bon temps officiel.</p><h3>4. Vérifier ses infos avant la course (code QR)</h3><p>Invitez les participants à scanner le code QR de l''événement pour consulter les résultats en ligne <strong>avant le départ</strong>. Ils pourront confirmer que leur nom, leur âge et leur numéro de dossard sont correctement associés à leur inscription.</p></article>',
'compte.php', 10, 1, NOW()),
('bib_dist_print', 'bib_dist_print_table', 'fr', 'Affiche table — participants', 'À placer sur la table de distribution',
'<article class="ms1-doc-article"><p><strong>Texte provisoire</strong> — Page destinée à être lue par les participants à la table.</p><h3>À faire avant de vous présenter</h3><ul><li>Ayez votre confirmation d''inscription ou une pièce d''identité.</li><li>Connaissez le nom de votre épreuve (ex. 10 km, demi-marathon).</li><li>Si vous êtes en équipe, présentez-vous ensemble si possible.</li></ul><h3>À la table</h3><ol><li>Donnez votre nom de famille clairement.</li><li>Vérifiez le numéro de dossard avant de quitter la table.</li><li>Épinglez le dossard bien visible à l''avant.</li></ol><p>Vous pouvez ajouter une image d''exemple ici, par ex. :</p><p><img src="/images/doc/exemple-table.png" alt="Exemple d''affichage"></p></article>',
@ -33,8 +33,8 @@ INSERT INTO `doc_page` (`doc_mod_clef`, `doc_page_clef`, `doc_langue`, `doc_titr
-- EN
-- ---------------------------------------------------------------------------
INSERT INTO `doc_page` (`doc_mod_clef`, `doc_page_clef`, `doc_langue`, `doc_titre`, `doc_sous_titre`, `doc_html`, `doc_prg`, `doc_tri`, `doc_actif`, `doc_creation`) VALUES
('bib_dist_print', 'bib_dist_print_reco', 'en', 'Recommendations — bib distribution', 'Read before you start',
'<article class="ms1-doc-article"><p><strong>Placeholder text (MSIN-4471)</strong> — Replace this content in the documentation editor.</p><h3>Basic rules</h3><ol><li>Verify the participant''s identity before handing out the bib.</li><li>Check or cross off the number on the printed list after each handout.</li><li>Keep unclaimed bibs in a clearly labeled separate bin.</li></ol><h3>Table setup</h3><ul><li>One person on the list, one on the bibs.</li><li>Prepare races in the order of the queues.</li></ul><blockquote>Image tip: place files under <strong>images/doc/</strong> then use &lt;img src="/images/doc/filename.png"&gt;.</blockquote></article>',
('bib_dist_print', 'bib_dist_print_reco', 'en', 'Distribution tips', 'For a smooth, error-free bib handout',
'<article class="ms1-doc-article"><p><em>Read before you start.</em> A few seconds at each handout prevent swaps, timing errors, and incorrect results.</p><h3>1. Families and groups — multiple bibs</h3><p>When handing out several bibs to the same family or group, make sure each bib shows a first name. If it is not already there, <strong>write it on the back</strong>. This way everyone leaves with the right number: a swap between relatives will skew timing and results.</p><h3>2. Do not give away your bib</h3><p>A bib registered under one name <strong>must not</strong> be given to someone else. If a swap has already happened, <strong>notify the organizers immediately</strong> so they can correct the database before the race.</p><h3>3. Bib clearly visible on the front</h3><p>Remind the participant to pin the bib <strong>clearly visible on the front of the torso</strong>. This is essential for reliable timing and an accurate official time.</p><h3>4. Check details before the race (QR code)</h3><p>Invite participants to scan the event QR code and view results online <strong>before the start</strong>. They can confirm that their name, age, and bib number are correctly linked to their registration.</p></article>',
'compte.php', 10, 1, NOW()),
('bib_dist_print', 'bib_dist_print_table', 'en', 'Table sign — participants', 'Place on the distribution table',
'<article class="ms1-doc-article"><p><strong>Placeholder</strong> — Page meant to be read by participants at the table.</p><h3>Before you come up</h3><ul><li>Have your registration confirmation or ID ready.</li><li>Know your race name (e.g. 10K, half marathon).</li><li>If you are a team, come together if possible.</li></ul><h3>At the table</h3><ol><li>Say your last name clearly.</li><li>Check the bib number before leaving the table.</li><li>Pin the bib clearly on the front.</li></ol><p>You can add a sample image here, e.g.:</p><p><img src="/images/doc/exemple-table.png" alt="Sample display"></p></article>',

View File

@ -0,0 +1,31 @@
-- MSIN-4471 — Libellés feuille bénévole PDF distribution (nom+prénom, case remise)
-- Prérequis : clés bib_v4_dist_print_* (MSIN-4433)
-- Idempotent : INSERT si absent ; UPDATE libellé max questions si présent
SET NAMES utf8mb4;
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_section, info_tri, info_actif, info_type, info_css, info_js, info_creation)
SELECT 'bib_v4_dist_print_col_nom_prenom', 'fr', 'Nom, Prénom', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (
SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_nom_prenom' AND info_langue = 'fr' AND info_prg = 'compte.php'
);
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_section, info_tri, info_actif, info_type, info_css, info_js, info_creation)
SELECT 'bib_v4_dist_print_col_nom_prenom', 'en', 'Last name, First name', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (
SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_nom_prenom' AND info_langue = 'en' AND info_prg = 'compte.php'
);
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_section, info_tri, info_actif, info_type, info_css, info_js, info_creation)
SELECT 'bib_v4_dist_print_col_check', 'fr', '', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (
SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_check' AND info_langue = 'fr' AND info_prg = 'compte.php'
);
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_section, info_tri, info_actif, info_type, info_css, info_js, info_creation)
SELECT 'bib_v4_dist_print_col_check', 'en', '', '', 'compte.php', '', 0, 1, '', '', '', NOW()
FROM DUAL WHERE NOT EXISTS (
SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_check' AND info_langue = 'en' AND info_prg = 'compte.php'
);
-- Le message max questions utilise %d via PHP (fxBibDistPrintMaxQuestions = 3) — pas de texte figé ici.