diff --git a/bib_dist_print.php b/bib_dist_print.php index fa4a876..a88111b 100644 --- a/bib_dist_print.php +++ b/bib_dist_print.php @@ -29,7 +29,8 @@ $_POST['eve_id'] = $int_eve_id; fxBibRequireDistPrintAccess(); $tabSelections = fxBibParseDistPrintSelectionsFromPost($_POST); -$tabSave = fxBibSaveDistPrintSelections($int_eve_id, $tabSelections, $strLangue); +$strOrient = fxBibDistPrintNormalizeOrient($_POST['dist_print_orient'] ?? 'P'); +$tabSave = fxBibSaveDistPrintSelections($int_eve_id, $tabSelections, $strLangue, $strOrient); if (!$tabSave['success']) { http_response_code(400); diff --git a/css/style.css b/css/style.css index feee69a..e993871 100644 --- a/css/style.css +++ b/css/style.css @@ -4074,6 +4074,41 @@ a.ms1-trad-link.btn-aide-trad{ cursor:pointer; } +.bib-dist-print-orient{ + border:1px solid #e9ecef; + border-radius:6px; + padding:10px 12px; + background:#f8fafc; +} + +.bib-dist-print-orient-legend{ + font-size:13px; + font-weight:600; + margin-bottom:6px; +} + +.bib-dist-print-orient-opt{ + display:inline-flex; + align-items:center; + gap:6px; + font-size:13px; + cursor:pointer; + margin:0; +} + +.bib-dist-print-fit-status{ + color:#495057; + margin-top:4px; +} + +.bib-dist-print-fit-warn{ + margin-top:4px; +} + +.bib-dist-print-cols--base{ + margin-bottom:8px; +} + .bib-dist-print-actions{ border-top:1px solid #e9ecef; padding-top:12px; diff --git a/js/v2/bib-assignments.js b/js/v2/bib-assignments.js index 96eeee8..54d3cc7 100644 --- a/js/v2/bib-assignments.js +++ b/js/v2/bib-assignments.js @@ -3193,7 +3193,7 @@ }); } - /** MSIN-4433 — Limite questions + rafraîchissement après génération PDF. */ + /** MSIN-4433 / MSIN-4512 — Fit colonnes (budget mm) + rafraîchissement après PDF. */ function initBibDistPrintPanel(root) { root = root || document; let panel = root.querySelector ? root.querySelector('#bib-dist-print-panel') : null; @@ -3205,29 +3205,93 @@ } panel.setAttribute('data-bib-dist-print-init', '1'); - let intMax = parseInt(panel.getAttribute('data-max-questions') || '5', 10); - if (!intMax || intMax < 1) { - intMax = 5; + function bibDistPrintBudget() { + let radio = panel.querySelector('.bib-dist-print-orient-radio:checked'); + let orient = radio ? String(radio.value || 'P') : 'P'; + let budget = parseInt( + panel.getAttribute(orient === 'L' ? 'data-budget-l' : 'data-budget-p') || '0', + 10 + ); + return budget > 0 ? budget : 100; + } + + function bibDistPrintUpdateFitUi(section) { + let budget = bibDistPrintBudget(); + let hint = panel.querySelector('.bib-dist-print-fit-hint'); + if (hint) { + let tpl = hint.getAttribute('data-hint-tpl') || ''; + if (tpl.indexOf('%d') !== -1) { + hint.textContent = tpl.replace('%d', String(budget)); + } + } + + let sections = section + ? [section] + : panel.querySelectorAll('.bib-dist-print-epr'); + let intMaxUsed = 0; + sections.forEach(function (sec) { + let used = 0; + sec.querySelectorAll('.bib-dist-print-col-cb:checked').forEach(function (cb) { + used += parseInt(cb.getAttribute('data-col-width') || '28', 10) || 28; + }); + if (used > intMaxUsed) { + intMaxUsed = used; + } + }); + + let status = panel.querySelector('.bib-dist-print-fit-status'); + let usedTpl = panel.getAttribute('data-fit-used-tpl') || '%d / %d'; + if (status) { + status.textContent = usedTpl + .replace('%d', String(intMaxUsed)) + .replace('%d', String(budget)); + } + + let warn = panel.querySelector('.bib-dist-print-fit-warn'); + if (warn) { + if (intMaxUsed > budget) { + warn.textContent = panel.getAttribute('data-fit-over') || ''; + warn.hidden = false; + } else { + warn.textContent = ''; + warn.hidden = true; + } + } } panel.addEventListener('change', function (ev) { - let cb = ev.target; - if (!cb || !cb.classList || !cb.classList.contains('bib-dist-print-question-cb')) { + let el = ev.target; + if (!el) { return; } - if (!cb.checked) { + if (el.classList && el.classList.contains('bib-dist-print-orient-radio')) { + bibDistPrintUpdateFitUi(null); return; } - let section = cb.closest('.bib-dist-print-epr'); + if (!el.classList || !el.classList.contains('bib-dist-print-col-cb')) { + return; + } + if (!el.checked) { + bibDistPrintUpdateFitUi(el.closest('.bib-dist-print-epr')); + return; + } + let section = el.closest('.bib-dist-print-epr'); if (!section) { return; } - let tabChecked = section.querySelectorAll('.bib-dist-print-question-cb:checked'); - if (tabChecked.length > intMax) { - cb.checked = false; + let budget = bibDistPrintBudget(); + let used = 0; + section.querySelectorAll('.bib-dist-print-col-cb:checked').forEach(function (cb) { + used += parseInt(cb.getAttribute('data-col-width') || '28', 10) || 28; + }); + if (used > budget) { + el.checked = false; } + bibDistPrintUpdateFitUi(section); }); + bibDistPrintUpdateFitUi(null); + let form = panel.querySelector('.bib-dist-print-form'); if (form) { form.addEventListener('submit', function () { diff --git a/php/inc_fx_bib_dist_print.php b/php/inc_fx_bib_dist_print.php new file mode 100644 index 0000000..c3f84cc --- /dev/null +++ b/php/inc_fx_bib_dist_print.php @@ -0,0 +1,364 @@ + 10, + 'no_bib_remis' => 14, + 'par_sexe' => 12, + 'par_age' => 12, + 'par_naissance' => 26, + 'par_ville' => 32, + 'par_telephone1' => 30, + 'par_telephone2' => 30, + 'par_courriel' => 40, + 'par_adresse' => 40, + 'par_adresse2' => 36, + 'par_codepostal' => 18, + 'pay_nom' => 28, + 'pay_id' => 28, + 'pay_iso' => 14, + 'nom_equipe' => 32, + 'par_nom_equipe' => 32, + 'par_contact_urgence_nom' => 32, + 'par_contact_urgence_telephone' => 30, + ]; + if (isset($tab[$strKey])) { + return $tab[$strKey]; + } + return 28; +} + +/** MSIN-4512 — Somme des largeurs estimées. */ +function fxBibDistPrintColsWidthSumMm(array $tabKeys) { + $flt = 0; + foreach ($tabKeys as $strKey) { + $flt += fxBibDistPrintColEstWidthMm($strKey); + } + return (int)ceil($flt); +} + +/** + * MSIN-4512 — Parse CSV de clés colonnes (col_check,par_sexe,que:12,…). + * @return array + */ +function fxBibParseDistPrintColKeys($strCsv) { + if ($strCsv === null || trim((string)$strCsv) === '') { + return []; + } + $out = []; + foreach (explode(',', (string)$strCsv) as $part) { + $str = trim($part); + if ($str === '') { + continue; + } + if (preg_match('/^que:(\d+)$/', $str, $m)) { + $str = 'que:' . (int)$m[1]; + } elseif (preg_match('/^par_[a-z0-9_]+$/i', $str)) { + $str = strtolower($str); + } elseif (preg_match('/^(col_check|no_bib_remis|pay_nom|pay_iso|pay_id|nom_equipe)$/i', $str)) { + $str = strtolower($str); + } else { + continue; + } + if (!in_array($str, $out, true)) { + $out[] = $str; + } + } + return $out; +} + +/** MSIN-4512 — Sérialise les clés colonnes. */ +function fxBibDistPrintColKeysToCsv(array $tabKeys) { + return implode(',', fxBibParseDistPrintColKeys(implode(',', $tabKeys))); +} + +/** + * MSIN-4512 — Catalogue colonnes de base proposables (hors questions). + * Même source fiche / Production Excel + case OK + check-in. + * + * @return array + */ +function fxBibDistPrintCollectBaseFieldOptions($int_eve_id, $strLangue = 'fr') { + $int_eve_id = (int)$int_eve_id; + $strLangue = ($strLangue === 'en') ? 'en' : 'fr'; + $tabOut = []; + $tabSeen = []; + + $fnAdd = function ($strKey, $strLabel) use (&$tabOut, &$tabSeen) { + $strKey = trim((string)$strKey); + $strLabel = trim((string)$strLabel); + if ($strKey === '' || isset($tabSeen[$strKey])) { + return; + } + // Obligatoires PDF : pas dans les options. + if (in_array($strKey, ['par_nom', 'par_prenom', 'par_prenom_nom', 'no_bib'], true)) { + return; + } + $tabSeen[$strKey] = true; + $tabOut[] = [ + 'key' => $strKey, + 'label' => $strLabel !== '' ? $strLabel : $strKey, + 'width' => fxBibDistPrintColEstWidthMm($strKey), + ]; + }; + + $fnAdd('col_check', fxBibTexte('bib_v4_dist_print_col_check_opt', 0)); + $fnAdd('no_bib_remis', fxBibTexte('bib_v4_dist_print_col_checkin', 0)); + + if (!function_exists('fxBibProductionGetEventInfoFields')) { + $strProd = __DIR__ . '/inc_fx_bib_production.php'; + if (is_file($strProd)) { + require_once $strProd; + } + } + + $blnHasSexe = false; + if ($int_eve_id > 0 && function_exists('fxBibProductionGetEventInfoFields')) { + foreach (fxBibProductionGetEventInfoFields($int_eve_id) as $tabInfo) { + $strCha = trim((string)($tabInfo['cha_nom'] ?? '')); + if ($strCha === '') { + continue; + } + if ($strCha === 'par_sexe') { + $blnHasSexe = true; + } + $strLabel = trim((string)($tabInfo['cha_label_' . $strLangue] ?? '')); + if ($strLabel === '') { + $strLabel = trim((string)($tabInfo['cha_label_fr'] ?? '')); + } + $fnAdd($strCha, $strLabel); + } + } + + if (!$blnHasSexe) { + $fnAdd('par_sexe', fxBibTexte('bib_v4_dist_print_col_sexe', 0)); + } + + // Pays : libellé (pas l'id brut) — comme Production Excel. + $fnAdd('pay_nom', fxBibTexte('bib_v5_production_field_pay_nom', 0) ?: (($strLangue === 'en') ? 'Country' : 'Pays')); + $fnAdd('nom_equipe', fxBibTexte('bib_v5_production_field_nom_equipe', 0) ?: (($strLangue === 'en') ? 'Team name' : 'Nom d\'équipe')); + + return $tabOut; +} + +/** + * MSIN-4512 — Sélection mémorisée (ba_bib_dist_cols) avec repli legacy que_ids. + * @return array + */ +function fxBibDistPrintResolveSelectedCols(array $eprRow, array $tabValidKeys) { + $tabValid = []; + foreach ($tabValidKeys as $strKey) { + $tabValid[$strKey] = true; + } + + $strCols = trim((string)($eprRow['ba_bib_dist_cols'] ?? '')); + if ($strCols !== '') { + $tabSel = fxBibParseDistPrintColKeys($strCols); + } else { + // Legacy : case OK + sexe (comportement PDF d’avant) + questions CSV. + $tabSel = ['col_check', 'par_sexe']; + foreach (fxBibParseDistPrintQueIds($eprRow['ba_bib_dist_que_ids'] ?? '') as $intQueId) { + $tabSel[] = 'que:' . (int)$intQueId; + } + } + + $tabOut = []; + foreach ($tabSel as $strKey) { + if (isset($tabValid[$strKey]) && !in_array($strKey, $tabOut, true)) { + $tabOut[] = $strKey; + } + } + return $tabOut; +} + +/** MSIN-4512 — Orientation mémorisée sur l’événement. */ +function fxBibGetDistPrintOrient($int_eve_id) { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + if ($int_eve_id <= 0) { + return 'P'; + } + // Colonne absente tant que sql/MSIN-4512 n’est pas passé → portrait. + static $blnHasCol = null; + if ($blnHasCol === null) { + $blnHasCol = ((int)$objDatabase->fxGetVar( + "SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'inscriptions_evenements' + AND COLUMN_NAME = 'eve_bib_dist_print_orient'" + ) > 0); + } + if (!$blnHasCol) { + return 'P'; + } + $str = $objDatabase->fxGetVar( + "SELECT eve_bib_dist_print_orient FROM inscriptions_evenements WHERE eve_id = $int_eve_id LIMIT 1" + ); + return fxBibDistPrintNormalizeOrient($str); +} + +/** MSIN-4512 — Persiste orientation listes. */ +function fxBibSaveDistPrintOrient($int_eve_id, $strOrient) { + global $objDatabase; + + $int_eve_id = (int)$int_eve_id; + if ($int_eve_id <= 0) { + return; + } + $strOrient = fxBibDistPrintNormalizeOrient($strOrient); + static $blnHasCol = null; + if ($blnHasCol === null) { + $blnHasCol = ((int)$objDatabase->fxGetVar( + "SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'inscriptions_evenements' + AND COLUMN_NAME = 'eve_bib_dist_print_orient'" + ) > 0); + } + if (!$blnHasCol) { + return; + } + $objDatabase->fxQuery( + "UPDATE inscriptions_evenements + SET eve_bib_dist_print_orient = '" . $objDatabase->fxEscape($strOrient) . "' + WHERE eve_id = $int_eve_id + LIMIT 1" + ); +} + +/** + * MSIN-4512 — Valeur cellule PDF pour une clé optionnelle. + */ +function fxBibDistPrintResolveColValue($strKey, array $row, array $tabAnswersByQue, $strLangue = 'fr') { + $strKey = trim((string)$strKey); + $strLangue = ($strLangue === 'en') ? 'en' : 'fr'; + + if ($strKey === 'col_check') { + return ''; + } + if ($strKey === 'no_bib_remis') { + return ((int)($row['no_bib_remis'] ?? 0) === 1) + ? fxBibTexte('bib_v4_dist_print_checkin_yes', 0) + : ''; + } + if ($strKey === 'par_sexe') { + return fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue); + } + if (preg_match('/^que:(\d+)$/', $strKey, $m)) { + return trim((string)($tabAnswersByQue[(int)$m[1]] ?? '')); + } + + if (!function_exists('fxBibProductionResolveCellValue')) { + $strProd = __DIR__ . '/inc_fx_bib_production.php'; + if (is_file($strProd)) { + require_once $strProd; + } + } + if (function_exists('fxBibProductionResolveCellValue')) { + $str = fxBibProductionResolveCellValue( + $strKey, + (int)($row['no_bib'] ?? 0), + '', + $row, + $tabAnswersByQue, + $strLangue + ); + if ($strKey === 'par_naissance' && $str !== '' && $str !== '0000-00-00') { + $ts = strtotime($str); + if ($ts !== false) { + return date(($strLangue === 'en') ? 'Y-m-d' : 'Y-m-d', $ts); + } + } + return $str; + } + + return trim((string)($row[$strKey] ?? '')); +} + +/** + * MSIN-4512 — Calcule largeurs PDF : name flexible + options proportionnelles au budget. + * + * @param array $tabOptCols + * @return array{name:float,opts:array,page:float} + */ +function fxBibDistPrintComputeLayoutWidths(array $tabOptCols, $strOrient) { + $fltPage = fxBibDistPrintUsableWidthMm($strOrient); + $fltBib = 22.0; + $fltNameMin = 50.0; + $fltOptNeed = 0.0; + foreach ($tabOptCols as $col) { + $fltOptNeed += (float)($col['width'] ?? fxBibDistPrintColEstWidthMm($col['key'] ?? '')); + } + + $fltRemain = $fltPage - $fltBib; + if ($fltOptNeed <= 0) { + return [ + 'name' => $fltRemain, + 'bib' => $fltBib, + 'opts' => [], + 'page' => $fltPage, + ]; + } + + // Si trop serré : compresser les options, garder un minimum nom. + $fltName = $fltNameMin; + $fltForOpts = max(10.0, $fltRemain - $fltName); + $fltScale = ($fltOptNeed > $fltForOpts) ? ($fltForOpts / $fltOptNeed) : 1.0; + if ($fltScale >= 1.0) { + // Place restante → élargir la colonne nom. + $fltName = $fltRemain - $fltOptNeed; + $fltScale = 1.0; + } + + $tabOptsW = []; + foreach ($tabOptCols as $col) { + $strKey = (string)($col['key'] ?? ''); + $fltW = (float)($col['width'] ?? fxBibDistPrintColEstWidthMm($strKey)) * $fltScale; + $tabOptsW[$strKey] = max(8.0, $fltW); + } + + return [ + 'name' => max($fltNameMin, $fltName), + 'bib' => $fltBib, + 'opts' => $tabOptsW, + 'page' => $fltPage, + ]; +} diff --git a/php/inc_fx_promoteur.php b/php/inc_fx_promoteur.php index e7e63fd..925378d 100644 --- a/php/inc_fx_promoteur.php +++ b/php/inc_fx_promoteur.php @@ -1,5 +1,6 @@ ['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_questions' => ['fr' => 'Questions', 'en' => 'Questions'], + 'bib_v4_dist_print_cols_base' => ['fr' => 'Champs de base', 'en' => 'Base fields'], + 'bib_v4_dist_print_col_check_opt' => ['fr' => 'Case OK (je l\'ai pris)', 'en' => 'OK box (handed out)'], + 'bib_v4_dist_print_col_checkin' => ['fr' => 'Dossard déjà remis', 'en' => 'Bib already handed out'], + 'bib_v4_dist_print_checkin_yes' => ['fr' => 'Oui', 'en' => 'Yes'], + 'bib_v4_dist_print_orient' => ['fr' => 'Orientation des listes', 'en' => 'List page orientation'], + 'bib_v4_dist_print_orient_portrait'=> ['fr' => 'Portrait', 'en' => 'Portrait'], + 'bib_v4_dist_print_orient_landscape'=> ['fr' => 'Paysage', 'en' => 'Landscape'], + 'bib_v4_dist_print_orient_hint' => ['fr' => 'Les pages d\'information du début restent toujours en portrait.', 'en' => 'Intro information pages always stay portrait.'], + 'bib_v4_dist_print_fit_hint' => ['fr' => 'Budget colonnes optionnelles : ~%d mm (dossard + nom/prénom toujours réservés). Passez en paysage pour plus de place.', 'en' => 'Optional column budget: ~%d mm (bib + name always reserved). Switch to landscape for more room.'], + 'bib_v4_dist_print_fit_over' => ['fr' => 'Trop de colonnes pour cette orientation — décochez-en ou passez en paysage.', 'en' => 'Too many columns for this orientation — uncheck some or switch to landscape.'], + 'bib_v4_dist_print_fit_used' => ['fr' => 'Utilisé : %d / %d mm', 'en' => 'Used: %d / %d mm'], '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.'], @@ -9869,14 +9881,21 @@ function fxBibSaveDistPrintMeta($int_eve_id, $int_com_id, $str_by) { } /** - * MSIN-4433 — Données panneau : épreuves, questions éligibles, sélection mémorisée. - * @return array{meta: array, epreuves: array>} + * MSIN-4433 / MSIN-4512 — Données panneau : épreuves, champs de base, questions, orientation. + * @return array{meta: array, orient: string, budget_mm: int, base_fields: 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' => []]; + $strOrient = fxBibGetDistPrintOrient($int_eve_id); + $tabOut = [ + 'meta' => fxBibGetDistPrintMeta($int_eve_id), + 'orient' => $strOrient, + 'budget_mm' => fxBibDistPrintOptionalBudgetMm($strOrient), + 'base_fields' => fxBibDistPrintCollectBaseFieldOptions($int_eve_id, $strLangue), + 'epreuves' => [], + ]; if ($int_eve_id <= 0) { return $tabOut; @@ -9901,14 +9920,17 @@ function fxBibCollectDistPrintPanelData($int_eve_id, $strLangue = 'fr') { } $tabQuestionOpts = fxBibGetQuestionSortOptions($epr_id, $int_eve_id, $strLangue); - $tabSelected = fxBibParseDistPrintQueIds($epr['ba_bib_dist_que_ids'] ?? ''); - $tabValidIds = []; + $tabValidKeys = []; + foreach ($tabOut['base_fields'] as $opt) { + $tabValidKeys[] = (string)($opt['key'] ?? ''); + } foreach ($tabQuestionOpts as $opt) { if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { - $tabValidIds[] = (int)$m[1]; + $tabValidKeys[] = 'que:' . (int)$m[1]; } } - $tabSelected = array_values(array_intersect($tabSelected, $tabValidIds)); + + $tabSelected = fxBibDistPrintResolveSelectedCols($epr, $tabValidKeys); $tabOut['epreuves'][] = [ 'epr_id' => $epr_id, @@ -9922,15 +9944,47 @@ function fxBibCollectDistPrintPanelData($int_eve_id, $strLangue = 'fr') { return $tabOut; } -/** MSIN-4433 — Parse sélections POST dist_print[epr_id][] = que_id. */ +/** + * MSIN-4433 / MSIN-4512 — Parse sélections POST dist_print_cols[epr_id][] = clé. + * Repli legacy dist_print[epr_id][] = que_id. + */ function fxBibParseDistPrintSelectionsFromPost(array $post) { - $tabRaw = $post['dist_print'] ?? []; - if (!is_array($tabRaw)) { - return []; + $out = []; + + $tabRaw = $post['dist_print_cols'] ?? null; + if (is_array($tabRaw)) { + foreach ($tabRaw as $mixEprId => $mixKeys) { + $epr_id = (int)$mixEprId; + if ($epr_id <= 0) { + continue; + } + if (!is_array($mixKeys)) { + $mixKeys = [$mixKeys]; + } + $tabKeys = []; + foreach ($mixKeys as $mixKey) { + $strKey = trim((string)$mixKey); + if ($strKey === '') { + continue; + } + $tabParsed = fxBibParseDistPrintColKeys($strKey); + foreach ($tabParsed as $strParsed) { + if (!in_array($strParsed, $tabKeys, true)) { + $tabKeys[] = $strParsed; + } + } + } + $out[$epr_id] = $tabKeys; + } + return $out; } - $out = []; - foreach ($tabRaw as $mixEprId => $mixQueIds) { + // Legacy : uniquement des que_id. + $tabLegacy = $post['dist_print'] ?? []; + if (!is_array($tabLegacy)) { + return []; + } + foreach ($tabLegacy as $mixEprId => $mixQueIds) { $epr_id = (int)$mixEprId; if ($epr_id <= 0) { continue; @@ -9938,24 +9992,24 @@ function fxBibParseDistPrintSelectionsFromPost(array $post) { if (!is_array($mixQueIds)) { $mixQueIds = [$mixQueIds]; } - $tabIds = []; + $tabKeys = ['col_check', 'par_sexe']; foreach ($mixQueIds as $mixQueId) { $intQueId = (int)$mixQueId; - if ($intQueId > 0 && !in_array($intQueId, $tabIds, true)) { - $tabIds[] = $intQueId; + if ($intQueId > 0) { + $tabKeys[] = 'que:' . $intQueId; } } - $out[$epr_id] = $tabIds; + $out[$epr_id] = fxBibParseDistPrintColKeys(implode(',', $tabKeys)); } return $out; } /** - * MSIN-4433 — Sauvegarde les questions cochées par épreuve (à la génération PDF). + * MSIN-4433 / MSIN-4512 — Sauvegarde colonnes cochées par épreuve (+ orientation événement). * @return array{success: bool, message?: string} */ -function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLangue = 'fr') { +function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLangue = 'fr', $strOrient = 'P') { global $objDatabase; $int_eve_id = (int)$int_eve_id; @@ -9963,8 +10017,15 @@ function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLan return ['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')]; } - $intMax = fxBibDistPrintMaxQuestions(); + $strOrient = fxBibDistPrintNormalizeOrient($strOrient); + fxBibSaveDistPrintOrient($int_eve_id, $strOrient); + + $intBudget = fxBibDistPrintOptionalBudgetMm($strOrient); $tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue); + $tabBaseKeys = []; + foreach ($tabPanel['base_fields'] as $opt) { + $tabBaseKeys[(string)($opt['key'] ?? '')] = true; + } foreach ($tabPanel['epreuves'] as $tabEpr) { $epr_id = (int)($tabEpr['epr_id'] ?? 0); @@ -9972,10 +10033,10 @@ function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLan continue; } - $tabValidIds = []; + $tabValidKeys = $tabBaseKeys; foreach ($tabEpr['questions'] as $opt) { if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { - $tabValidIds[] = (int)$m[1]; + $tabValidKeys['que:' . (int)$m[1]] = true; } } @@ -9985,27 +10046,58 @@ function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLan } $tabFiltered = []; - foreach ($tabChosen as $intQueId) { - $intQueId = (int)$intQueId; - if ($intQueId > 0 && in_array($intQueId, $tabValidIds, true) - && !in_array($intQueId, $tabFiltered, true)) { - $tabFiltered[] = $intQueId; + $intUsed = 0; + foreach ($tabChosen as $strKey) { + $strKey = trim((string)$strKey); + if ($strKey === '' || empty($tabValidKeys[$strKey]) || in_array($strKey, $tabFiltered, true)) { + continue; + } + $intW = fxBibDistPrintColEstWidthMm($strKey); + // MSIN-4512 — Couper plutôt que bloquer si dépassement (comme max questions avant). + if ($intUsed + $intW > $intBudget && !empty($tabFiltered)) { + continue; + } + $tabFiltered[] = $strKey; + $intUsed += $intW; + } + + $strCsv = fxBibDistPrintColKeysToCsv($tabFiltered); + $tabQueOnly = []; + foreach ($tabFiltered as $strKey) { + if (preg_match('/^que:(\d+)$/', $strKey, $m)) { + $tabQueOnly[] = (int)$m[1]; } } + $strQueCsv = fxBibDistPrintQueIdsToCsv($tabQueOnly); - if (count($tabFiltered) > $intMax) { - // MSIN-4471 — Max abaissé à 3 : garder les N premières plutôt que bloquer. - $tabFiltered = array_slice($tabFiltered, 0, $intMax); + static $blnHasColsCol = null; + if ($blnHasColsCol === null) { + $blnHasColsCol = ((int)$objDatabase->fxGetVar( + "SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'inscriptions_epreuves' + AND COLUMN_NAME = 'ba_bib_dist_cols'" + ) > 0); } - $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 - "; + if ($blnHasColsCol) { + $sql = " + UPDATE inscriptions_epreuves + SET ba_bib_dist_cols = '" . $objDatabase->fxEscape($strCsv) . "', + ba_bib_dist_que_ids = '" . $objDatabase->fxEscape($strQueCsv) . "' + WHERE epr_id = $epr_id + AND eve_id = $int_eve_id + LIMIT 1 + "; + } else { + $sql = " + UPDATE inscriptions_epreuves + SET ba_bib_dist_que_ids = '" . $objDatabase->fxEscape($strQueCsv) . "' + WHERE epr_id = $epr_id + AND eve_id = $int_eve_id + LIMIT 1 + "; + } $objDatabase->fxQuery($sql); } @@ -10013,10 +10105,8 @@ function fxBibSaveDistPrintSelections($int_eve_id, array $tabSelections, $strLan } /** - * 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> + * MSIN-4433 / MSIN-4471 / MSIN-4512 — Participants avec dossard (une ligne par no_bib). + * Charge p.* + pec_nom_equipe pour les colonnes de base. */ function fxBibGetParticipantsForDistPrint($epr_id, $sort1, $sort2 = '', $strLangue = 'fr') { global $objDatabase; @@ -10032,13 +10122,8 @@ function fxBibGetParticipantsForDistPrint($epr_id, $sort1, $sort2 = '', $strLang $sql = " SELECT - p.par_id, - p.par_id_original, - p.pec_id, - p.no_bib, - p.par_nom, - p.par_prenom, - p.par_sexe + p.*, + c.pec_nom_equipe FROM resultats_participants p LEFT JOIN resultats_epreuves_commandees c ON c.pec_id_original = p.pec_id @@ -10965,16 +11050,19 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = $pdf->SetAutoPageBreak(true, 18); $pdf->AliasNbPages(); - // MSIN-4471 — Pages d'explication (doc) avant les tableaux d'épreuves. + // MSIN-4471 — Pages d'explication (doc) avant les tableaux d'épreuves (toujours portrait). fxBibOutputDistPrintIntroPages($pdf, $int_eve_id, $strLangue); - // MSIN-4471 — Feuille bénévole : recherche par nom, puis dossard à remettre. - // Ordre : ☐ | Nom, Prénom | Dossard | Sexe | questions - $fltPageW = $pdf->GetPageWidth() - 20; - $fltColCheck = 10; - $fltColBib = 28; - $fltColSexe = 12; - $fltFixedW = $fltColCheck + $fltColBib + $fltColSexe; + // MSIN-4512 — Orientation listes seulement (intro reste P). + $strListOrient = fxBibDistPrintNormalizeOrient($tabPanel['orient'] ?? 'P'); + $tabBaseByKey = []; + foreach (($tabPanel['base_fields'] ?? []) as $opt) { + $strK = (string)($opt['key'] ?? ''); + if ($strK !== '') { + $tabBaseByKey[$strK] = $opt; + } + } + $fltRowH = 8; $fltHeadH = 8; $fltBottom = method_exists($pdf, 'GetBreakMargin') ? $pdf->GetBreakMargin() : 14; @@ -10991,58 +11079,75 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = continue; } - // MSIN-4471 — Tri nom/prénom forcé dans fxBibGetParticipantsForDistPrint (args ignorés). $tabParticipants = fxBibGetParticipantsForDistPrint($epr_id, 'ba:2', '', $strLangue); - // MSIN-4433 — Épreuve sans dossard assigné : ne pas imprimer la section. if (empty($tabParticipants)) { continue; } - $tabSelectedQue = $tabEpr['selected'] ?? []; - $tabQueCols = []; - foreach ($tabEpr['questions'] as $opt) { - if (preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { + $tabSelected = $tabEpr['selected'] ?? []; + if (!is_array($tabSelected)) { + $tabSelected = []; + } + + $tabQueIds = []; + $tabOptCols = []; + foreach ($tabSelected as $strKey) { + $strKey = trim((string)$strKey); + if ($strKey === '') { + continue; + } + if (preg_match('/^que:(\d+)$/', $strKey, $m)) { $intQueId = (int)$m[1]; - if (in_array($intQueId, $tabSelectedQue, true)) { - $tabQueCols[] = [ - 'que_id' => $intQueId, - 'label' => (string)($opt['label'] ?? ('Q' . $intQueId)), - ]; + $tabQueIds[] = $intQueId; + $strLabel = 'Q' . $intQueId; + foreach ($tabEpr['questions'] as $opt) { + if ((string)($opt['key'] ?? '') === $strKey) { + $strLabel = (string)($opt['label'] ?? $strLabel); + break; + } } + $tabOptCols[] = [ + 'key' => $strKey, + 'label' => $strLabel, + 'width' => fxBibDistPrintColEstWidthMm($strKey), + ]; + continue; + } + if (isset($tabBaseByKey[$strKey])) { + $tabOptCols[] = [ + 'key' => $strKey, + 'label' => (string)($tabBaseByKey[$strKey]['label'] ?? $strKey), + 'width' => (int)($tabBaseByKey[$strKey]['width'] ?? fxBibDistPrintColEstWidthMm($strKey)), + ]; } } - // MSIN-4471 — Max 3 questions affichées (lisibilité feuille bénévole). - if (count($tabQueCols) > fxBibDistPrintMaxQuestions()) { - $tabQueCols = array_slice($tabQueCols, 0, fxBibDistPrintMaxQuestions()); - } - $intNbQ = count($tabQueCols); - $fltNameW = 78; - $fltQTotal = max(0, $fltPageW - $fltFixedW - $fltNameW); - if ($intNbQ === 0) { - $fltNameW = $fltPageW - $fltFixedW; - $fltQEach = 0; - } else { - $fltQEach = $fltQTotal / $intNbQ; - } + $tabLayout = fxBibDistPrintComputeLayoutWidths($tabOptCols, $strListOrient); + $fltNameW = (float)$tabLayout['name']; + $fltColBib = (float)$tabLayout['bib']; + $tabOptW = $tabLayout['opts']; + $intNbOpt = count($tabOptCols); $pdf->eprTitle = fxBibDistPrintTruncate($tabEpr['epr_label'] ?? '', 90); - $pdf->AddPage(); + $pdf->AddPage($strListOrient); $blnHasPrintedEpreuve = true; - $tabAnswers = fxBibGetDistPrintQuestionAnswers($epr_id, $tabSelectedQue, $tabParticipants, $strLangue); + $tabAnswers = fxBibGetDistPrintQuestionAnswers($epr_id, $tabQueIds, $tabParticipants, $strLangue); - $fnDrawTableHeader = function () use ($pdf, $fltColCheck, $fltColBib, $fltNameW, $fltColSexe, $fltQEach, $tabQueCols, $intNbQ, $fltHeadH) { - $pdf->SetFont('Arial', 'B', 10); + $fnDrawTableHeader = function () use ($pdf, $fltColBib, $fltNameW, $tabOptCols, $tabOptW, $intNbOpt, $fltHeadH) { + $pdf->SetFont('Arial', 'B', 9); $pdf->SetFillColor(220, 220, 220); - // Case remise | Nom (recherche) | Dossard | Sexe | … - $pdf->Cell($fltColCheck, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_check', 0)), 1, 0, 'C', true); + // Obligatoires : Nom, Prénom | Dossard — options ensuite. $pdf->Cell($fltNameW, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_nom_prenom', 0)), 1, 0, 'L', true); - $pdf->Cell($fltColBib, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_bib', 0)), 1, 0, 'C', true); - $pdf->Cell($fltColSexe, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_sexe', 0)), 1, $intNbQ === 0 ? 1 : 0, 'C', true); - foreach ($tabQueCols as $i => $col) { - $blnLast = ($i === $intNbQ - 1); - $pdf->Cell($fltQEach, $fltHeadH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($col['label'], 18)), 1, $blnLast ? 1 : 0, 'L', true); + $pdf->Cell($fltColBib, $fltHeadH, fxBibDistPrintPdfText(fxBibTexte('bib_v4_dist_print_col_bib', 0)), 1, $intNbOpt === 0 ? 1 : 0, 'C', true); + foreach ($tabOptCols as $i => $col) { + $strKey = (string)$col['key']; + $fltW = (float)($tabOptW[$strKey] ?? 20); + $strHead = ($strKey === 'col_check') + ? fxBibTexte('bib_v4_dist_print_col_check', 0) + : (string)$col['label']; + $blnLast = ($i === $intNbOpt - 1); + $pdf->Cell($fltW, $fltHeadH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strHead, 16)), 1, $blnLast ? 1 : 0, 'C', true); } }; @@ -11050,13 +11155,12 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = $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(); + $pdf->AddPage($strListOrient); $fnDrawTableHeader(); } - $strKey = fxBibDistPrintAnswerKey($row); + $strKeyAns = fxBibDistPrintAnswerKey($row); $strNom = trim((string)($row['par_nom'] ?? '')); $strPrenom = trim((string)($row['par_prenom'] ?? '')); $strNomPrenom = $strNom; @@ -11065,34 +11169,31 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = } $blnAlt = ($intRow % 2) === 1; - if ($blnAlt) { - $pdf->SetFillColor(245, 245, 245); - } else { - $pdf->SetFillColor(255, 255, 255); - } + $pdf->SetFillColor($blnAlt ? 245 : 255, $blnAlt ? 245 : 255, $blnAlt ? 245 : 255); $blnFill = true; + $tabAnsQue = $tabAnswers[$strKeyAns] ?? []; - // Case à cocher (vide) pour marquer la remise. - $pdf->SetFont('Arial', '', 11); - $pdf->Cell($fltColCheck, $fltRowH, '', 1, 0, 'C', $blnFill); - - // Nom, Prénom — colonne de recherche principale. $pdf->SetFont('Arial', 'B', 11); $pdf->Cell($fltNameW, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strNomPrenom, 42)), 1, 0, 'L', $blnFill); - // Dossard — numéro à remettre. $pdf->SetFont('Arial', 'B', 14); - $pdf->Cell($fltColBib, $fltRowH, fxBibDistPrintPdfText((string)(int)($row['no_bib'] ?? 0)), 1, 0, 'C', $blnFill); + $pdf->Cell($fltColBib, $fltRowH, fxBibDistPrintPdfText((string)(int)($row['no_bib'] ?? 0)), 1, $intNbOpt === 0 ? 1 : 0, 'C', $blnFill); - $pdf->SetFont('Arial', '', 11); - $pdf->Cell($fltColSexe, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue)), 1, $intNbQ === 0 ? 1 : 0, 'C', $blnFill); - - foreach ($tabQueCols as $i => $col) { - $intQueId = (int)$col['que_id']; - $strAns = $tabAnswers[$strKey][$intQueId] ?? ''; - $blnLast = ($i === $intNbQ - 1); - $pdf->SetFont('Arial', '', 10); - $pdf->Cell($fltQEach, $fltRowH, fxBibDistPrintPdfText(fxBibDistPrintTruncate($strAns, 20)), 1, $blnLast ? 1 : 0, 'L', $blnFill); + foreach ($tabOptCols as $i => $col) { + $strColKey = (string)$col['key']; + $fltW = (float)($tabOptW[$strColKey] ?? 20); + $blnLast = ($i === $intNbOpt - 1); + $strVal = fxBibDistPrintResolveColValue($strColKey, $row, $tabAnsQue, $strLangue); + $pdf->SetFont('Arial', '', ($strColKey === 'col_check') ? 11 : 9); + $pdf->Cell( + $fltW, + $fltRowH, + fxBibDistPrintPdfText(fxBibDistPrintTruncate($strVal, 22)), + 1, + $blnLast ? 1 : 0, + ($strColKey === 'col_check' || $strColKey === 'no_bib_remis' || $strColKey === 'par_sexe') ? 'C' : 'L', + $blnFill + ); } $intRow++; @@ -11102,7 +11203,7 @@ function fxBibOutputDistPrintPdf($int_eve_id, $strLangue = 'fr', $strPrintedBy = } if (!$blnHasPrintedEpreuve && $pdf->PageNo() < 1) { - $pdf->AddPage(); + $pdf->AddPage($strListOrient); } $strFilename = 'distribution-dossards-' . $int_eve_id . '.pdf'; @@ -11158,7 +11259,7 @@ function renderBibDistPrintPanelShell($int_eve_id, $strLangue = 'fr') { return ob_get_clean(); } -/** MSIN-4433 — Panneau impression PDF (formulaire + choix questions). */ +/** MSIN-4433 / MSIN-4512 — Panneau impression PDF (colonnes de base + questions + orientation). */ function renderBibDistPrintPanel($int_eve_id, $strLangue = 'fr', $tabPanel = null) { global $vDomaine; @@ -11169,8 +11270,14 @@ function renderBibDistPrintPanel($int_eve_id, $strLangue = 'fr', $tabPanel = nul $tabMeta = $tabPanel['meta'] ?? []; $tabEpreuves = $tabPanel['epreuves'] ?? []; - $intMaxQ = fxBibDistPrintMaxQuestions(); + $tabBaseFields = $tabPanel['base_fields'] ?? []; + $strOrient = fxBibDistPrintNormalizeOrient($tabPanel['orient'] ?? 'P'); + $intBudgetP = fxBibDistPrintOptionalBudgetMm('P'); + $intBudgetL = fxBibDistPrintOptionalBudgetMm('L'); + $intBudget = ($strOrient === 'L') ? $intBudgetL : $intBudgetP; $strPrintUrl = $vDomaine . '/bib_dist_print.php'; + $strFitOver = fxBibTexte('bib_v4_dist_print_fit_over', 0); + $strFitUsedTpl = fxBibTexte('bib_v4_dist_print_fit_used', 0); ob_start(); ?> @@ -11179,13 +11286,15 @@ function renderBibDistPrintPanel($int_eve_id, $strLangue = 'fr', $tabPanel = nul data-bib-tool="dist_print" data-eve-id="" data-bib-dist-print-loaded="1" - data-max-questions=""> + data-budget-p="" + data-budget-l="" + data-fit-over="" + data-fit-used-tpl="">

-

- -

+
+ + + + + + +

+ +

+

+ +

+

+ +
+ () + +
+ + + + +
    + +
  • + +
  • + +
+
+

-
+
@@ -11248,15 +11416,17 @@ function renderBibDistPrintPanel($int_eve_id, $strLangue = 'fr', $tabPanel = nul if (!preg_match('/^que:(\d+)$/', (string)($opt['key'] ?? ''), $m)) { continue; } - $intQueId = (int)$m[1]; - $blnChecked = in_array($intQueId, $tabSelected, true); + $strQueKey = 'que:' . (int)$m[1]; + $blnChecked = in_array($strQueKey, $tabSelected, true); + $intW = fxBibDistPrintColEstWidthMm($strQueKey); ?>
  • diff --git a/php/inc_settings.php b/php/inc_settings.php index 185396b..f9eb2f9 100644 --- a/php/inc_settings.php +++ b/php/inc_settings.php @@ -7,7 +7,7 @@ * Constantes * * **************/ -define('_VERSION_CODE', '4.72.922'); // MSIN-4532 — ordre fiche : Enregistrer puis statut/remis/annulation +define('_VERSION_CODE', '4.72.923'); // MSIN-4512 — PDF dist : colonnes de base + orientation listes define('_DATE_CODE', '2026-07-30'); //MSIN-4290 define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe'); diff --git a/sql/MSIN-4512-dist-print-colonnes-base.sql b/sql/MSIN-4512-dist-print-colonnes-base.sql new file mode 100644 index 0000000..a31bf37 --- /dev/null +++ b/sql/MSIN-4512-dist-print-colonnes-base.sql @@ -0,0 +1,122 @@ +-- MSIN-4512 — PDF distribution : colonnes de base + orientation listes +-- Prérequis : sql/MSIN-4433-bib-distribution-pdf.sql +-- Notes : exécution UNIQUEMENT sur dev préprod ; autres env = Navicat structure + sync_static_db + +SET @db := DATABASE(); + +-- Colonnes optionnelles mémorisées par épreuve (clés CSV : col_check,par_sexe,que:12,…) +SET @col_dist_cols := ( + SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'inscriptions_epreuves' AND COLUMN_NAME = 'ba_bib_dist_cols' +); +SET @sql_dist_cols := IF( + @col_dist_cols = 0, + 'ALTER TABLE inscriptions_epreuves ADD COLUMN ba_bib_dist_cols TEXT NULL COMMENT ''MSIN-4512 — colonnes optionnelles PDF distribution (CSV)'' AFTER ba_bib_dist_que_ids', + 'SELECT ''ba_bib_dist_cols already exists'' AS note' +); +PREPARE stmt_dist_cols FROM @sql_dist_cols; +EXECUTE stmt_dist_cols; +DEALLOCATE PREPARE stmt_dist_cols; + +-- Orientation des pages de liste seulement (P=portrait, L=paysage) +SET @col_orient := ( + SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'inscriptions_evenements' AND COLUMN_NAME = 'eve_bib_dist_print_orient' +); +SET @sql_orient := IF( + @col_orient = 0, + 'ALTER TABLE inscriptions_evenements ADD COLUMN eve_bib_dist_print_orient CHAR(1) NOT NULL DEFAULT ''P'' COMMENT ''MSIN-4512 — P/L listes PDF dist (intro reste portrait)'' AFTER eve_bib_dist_print_com_id', + 'SELECT ''eve_bib_dist_print_orient already exists'' AS note' +); +PREPARE stmt_orient FROM @sql_orient; +EXECUTE stmt_orient; +DEALLOCATE PREPARE stmt_orient; + +-- Libellés Info (compte.php) +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_cols_base', 'fr', 'Champs de base', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_cols_base' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_cols_base', 'en', 'Base fields', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_cols_base' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_col_check_opt', 'fr', 'Case OK (je l''ai pris)', 'Petit carré vide à cocher à la main sur le papier.', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_check_opt' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_col_check_opt', 'en', 'OK box (handed out)', 'Empty checkbox to tick by hand on paper.', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_check_opt' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_col_checkin', 'fr', 'Dossard déjà remis', 'Indique si le check-in (no_bib_remis) est déjà fait.', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_checkin' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_col_checkin', 'en', 'Bib already handed out', 'Shows whether check-in (no_bib_remis) is already done.', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_col_checkin' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_checkin_yes', 'fr', 'Oui', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_checkin_yes' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_checkin_yes', 'en', 'Yes', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_checkin_yes' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient', 'fr', 'Orientation des listes', 'S''applique seulement aux pages de liste. Les pages d''information du début restent en portrait.', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient', 'en', 'List page orientation', 'Applies to list pages only. Intro information pages stay portrait.', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient_portrait', 'fr', 'Portrait', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient_portrait' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient_portrait', 'en', 'Portrait', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient_portrait' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient_landscape', 'fr', 'Paysage', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient_landscape' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient_landscape', 'en', 'Landscape', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient_landscape' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient_hint', 'fr', 'Les pages d''information du début restent toujours en portrait.', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient_hint' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_orient_hint', 'en', 'Intro information pages always stay portrait.', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_orient_hint' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_fit_hint', 'fr', 'Budget colonnes optionnelles : ~%d mm (dossard + nom/prénom toujours réservés). Passez en paysage pour plus de place.', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_fit_hint' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_fit_hint', 'en', 'Optional column budget: ~%d mm (bib + name always reserved). Switch to landscape for more room.', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_fit_hint' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_fit_over', 'fr', 'Trop de colonnes pour cette orientation — décochez-en ou passez en paysage.', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_fit_over' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_fit_over', 'en', 'Too many columns for this orientation — uncheck some or switch to landscape.', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_fit_over' AND info_langue = 'en' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_fit_used', 'fr', 'Utilisé : %d / %d mm', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_fit_used' AND info_langue = 'fr' AND info_prg = 'compte.php'); + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) +SELECT 'bib_v4_dist_print_fit_used', 'en', 'Used: %d / %d mm', '', 'compte.php', '', 0, 1, '', '', '', NOW() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_dist_print_fit_used' AND info_langue = 'en' AND info_prg = 'compte.php');