MSIN-4578 — Updated bib and chip order management functionality. Enhanced UI elements and CSS for better readability and usability. Adjusted PHP functions to support new milestone and actual date reporting, including improved localization for user interface texts. Incremented version to 4.73.037 to reflect these changes.

This commit is contained in:
2026-08-19 16:56:47 -04:00
parent fd74116911
commit 78286540fe
6 changed files with 110 additions and 74 deletions

View File

@ -7429,7 +7429,7 @@ button.inscr-gestion-list-remis:hover{
}
}
/* MSIN-4578 — Gestionnaire de dossards (ops global, temporaire) */
/* MSIN-4578 — Gestionnaire de commande de dossards et puces (ops global, temporaire) */
.promoteur-hub-bib-ops{
padding:14px 16px;
background:#f4f7fb;
@ -7439,20 +7439,39 @@ button.inscr-gestion-list-remis:hover{
}
.bib-ops-table{
margin-bottom:0;
color:#222;
}
/* .table thead du site est orange (#f3a566) — illisible avec un texte coloré. */
.bib-ops-table.table thead tr{
background:#eef1f4;
color:#222;
}
.bib-ops-table th{
white-space:nowrap;
font-weight:600;
color:#1f3b63;
border-bottom:2px solid #f3a566;
color:#222;
border-bottom:1px solid #c5cdd5;
vertical-align:middle;
}
.bib-ops-due.is-overdue{
.bib-ops-table th.bib-ops-th-ms{
text-align:center;
white-space:normal;
min-width:9.5em;
border-left:1px solid #d5dde5;
}
.bib-ops-table th.bib-ops-th-sub{
font-weight:500;
font-size:12px;
color:#444;
white-space:nowrap;
border-left:1px solid #d5dde5;
}
.bib-ops-table td.bib-ops-jalon,
.bib-ops-table td.bib-ops-real{
white-space:nowrap;
font-variant-numeric:tabular-nums;
border-left:1px solid #e8eef4;
}
.bib-ops-jalon.is-overdue{
color:#b3261e;
font-weight:600;
}
.bib-ops-due.is-done{
color:#2e7d4f;
}
.bib-ops-done-mark{
font-weight:700;
}

View File

@ -45,8 +45,7 @@ if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
$tabEvents = $objDatabase->fxGetResults(
"SELECT e.eve_id, e.eve_nom_fr, e.eve_nom_en,
e.eve_date_debut, e.eve_date_fin,
e.eve_lieu_fr, e.eve_lieu_en
e.eve_date_debut, e.eve_date_fin
FROM inscriptions_evenements e
WHERE e.eve_actif = 1
AND (
@ -82,14 +81,9 @@ if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
if ($strNom === '') {
$strNom = trim((string)($tabRow['eve_nom_' . $strAlt] ?? ''));
}
$strLieu = trim((string)($tabRow['eve_lieu_' . $strLangue] ?? ''));
if ($strLieu === '') {
$strLieu = trim((string)($tabRow['eve_lieu_' . $strAlt] ?? ''));
}
$tabOut[$intEveId] = [
'eve_id' => $intEveId,
'nom' => $strNom,
'lieu' => $strLieu,
'date_label' => fxBibOpsFormatEventDate($tabRow),
'milestones' => [],
];
@ -164,6 +158,19 @@ if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
return $intTs < strtotime(date('Y-m-d'));
}
/** Date seule (Y-m-d) pour le rapport ops — pas lheure. */
function fxBibOpsFormatReportDate($strValue) {
$strValue = trim((string)$strValue);
if ($strValue === '' || strpos($strValue, '0000-00-00') === 0) {
return '';
}
$intTs = strtotime($strValue);
if ($intTs <= 0) {
return '';
}
return date('Y-m-d', $intTs);
}
function fxBibOpsRenderDashboard($strLangue = 'fr') {
$strLangue = ($strLangue === 'en') ? 'en' : 'fr';
$tabEvents = fxBibOpsLoadUpcomingBibEvents($strLangue);
@ -172,8 +179,9 @@ if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
: [];
$strEmptyDue = fxBibTexte('bib_v5_ops_due_empty', 0);
$strOverdue = fxBibTexte('bib_v5_ops_overdue', 0);
$strDone = fxBibTexte('bib_v5_ops_done', 0);
$strOpen = fxBibTexte('bib_v5_ops_open', 0);
$strJalon = fxBibTexte('bib_v5_cmd_jalon', 0);
$strRealite = fxBibTexte('bib_v5_cmd_realite', 0);
$html = '<div class="bib-ops-page">';
$html .= '<div class="bib-cmd-pagebar">';
@ -194,13 +202,20 @@ if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
$html .= '<div class="table-responsive bib-ops-table-wrap">';
$html .= '<table class="table table-sm bib-ops-table">';
$html .= '<thead><tr>';
$html .= '<th>' . fxBibEsc(fxBibTexte('bib_v5_ops_col_event', 0)) . '</th>';
$html .= '<th>' . fxBibEsc(fxBibTexte('bib_v5_ops_col_dates', 0)) . '</th>';
$html .= '<thead>';
$html .= '<tr>';
$html .= '<th rowspan="2">' . fxBibEsc(fxBibTexte('bib_v5_ops_col_event', 0)) . '</th>';
$html .= '<th rowspan="2">' . fxBibEsc(fxBibTexte('bib_v5_ops_col_dates', 0)) . '</th>';
foreach ($tabKinds as $strKind) {
$html .= '<th>' . fxBibEsc(fxBibTexte('bib_v5_cmd_ms_' . $strKind, 0)) . '</th>';
$html .= '<th class="bib-ops-th-ms" colspan="2">'
. fxBibEsc(fxBibTexte('bib_v5_cmd_ms_' . $strKind, 0)) . '</th>';
}
$html .= '<th rowspan="2"></th>';
$html .= '</tr><tr>';
foreach ($tabKinds as $strKind) {
$html .= '<th class="bib-ops-th-sub">' . fxBibEsc($strJalon) . '</th>';
$html .= '<th class="bib-ops-th-sub">' . fxBibEsc($strRealite) . '</th>';
}
$html .= '<th></th>';
$html .= '</tr></thead><tbody>';
foreach ($tabEvents as $tabEve) {
@ -209,40 +224,25 @@ if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
? fxBibCommandePageUrl($intEveId, $strLangue)
: '#';
$html .= '<tr>';
$html .= '<td><strong>' . fxBibEsc($tabEve['nom']) . '</strong>';
if ($tabEve['lieu'] !== '') {
$html .= '<div class="text-muted small">' . fxBibEsc($tabEve['lieu']) . '</div>';
}
$html .= '</td>';
$html .= '<td>' . fxBibEsc($tabEve['nom']) . '</td>';
$html .= '<td class="text-nowrap">' . fxBibEsc($tabEve['date_label']) . '</td>';
foreach ($tabKinds as $strKind) {
$tabMs = $tabEve['milestones'][$strKind] ?? ['due' => null, 'done_at' => null];
$strDue = (string)($tabMs['due'] ?? '');
$strDoneAt = (string)($tabMs['done_at'] ?? '');
$strDue = fxBibOpsFormatReportDate($tabMs['due'] ?? '');
$strDoneAt = fxBibOpsFormatReportDate($tabMs['done_at'] ?? '');
$blnOverdue = fxBibOpsDueIsOverdue($strDue, $strDoneAt);
$strClass = 'bib-ops-due';
if ($strDoneAt !== '') {
$strClass .= ' is-done';
} elseif ($blnOverdue) {
$strClass .= ' is-overdue';
}
$strLabel = ($strDue !== '') ? $strDue : $strEmptyDue;
$strTitle = '';
$strDueClass = 'bib-ops-jalon';
if ($blnOverdue) {
$strTitle = $strOverdue;
} elseif ($strDoneAt !== '') {
$strTitle = $strDone;
$strDueClass .= ' is-overdue';
}
$html .= '<td class="' . $strClass . '"';
if ($strTitle !== '') {
$html .= ' title="' . fxBibEsc($strTitle) . '"';
$html .= '<td class="' . $strDueClass . '"';
if ($blnOverdue) {
$html .= ' title="' . fxBibEsc($strOverdue) . '"';
}
$html .= '>' . fxBibEsc($strLabel);
if ($strDoneAt !== '') {
$html .= '<span class="bib-ops-done-mark" aria-hidden="true"> ✓</span>';
}
$html .= '</td>';
$html .= '>' . fxBibEsc($strDue !== '' ? $strDue : $strEmptyDue) . '</td>';
$html .= '<td class="bib-ops-real">'
. fxBibEsc($strDoneAt !== '' ? $strDoneAt : $strEmptyDue) . '</td>';
}
$html .= '<td class="text-nowrap"><a class="btn btn-sm btn-outline-primary rounded-pill" href="'

View File

@ -4107,8 +4107,8 @@ function fxBibStaticFallback($clef) {
'bib_v5_cmd_sql_missing' => ['fr' => 'Structure absente — exécuter sql/MSIN-4577-commande-dossards-puces.sql en dev préprod.', 'en' => 'Missing structure — run sql/MSIN-4577-commande-dossards-puces.sql on dev preprod.'],
'bib_v5_cmd_unauthorized' => ['fr' => 'Cette page est réservée à la préparation de commande.', 'en' => 'This page is for order preparation only.'],
// MSIN-4578 — Tableau de bord ops global (filet si Info pas encore sync)
'bib_v5_ops_page_title' => ['fr' => 'Gestionnaire de dossards', 'en' => 'Bib manager'],
'bib_v5_ops_intro' => ['fr' => 'Événements à venir qui ont des séquences de dossards. Les dates sont les jalons saisis sur la commande.', 'en' => 'Upcoming events that have bib ranges. Dates are the milestones entered on the order.'],
'bib_v5_ops_page_title' => ['fr' => 'Gestionnaire de commande de dossards et puces', 'en' => 'Bib and chip order manager'],
'bib_v5_ops_intro' => ['fr' => 'Événements à venir qui ont des séquences de dossards. Pour chaque jalon : la date cible, puis la date réelle.', 'en' => 'Upcoming events that have bib ranges. For each milestone: the due date, then the actual date.'],
'bib_v5_ops_back' => ['fr' => 'Retour au tableau de bord', 'en' => 'Back to dashboard'],
'bib_v5_ops_col_event' => ['fr' => 'Événement', 'en' => 'Event'],
'bib_v5_ops_col_dates' => ['fr' => 'Dates événement', 'en' => 'Event dates'],
@ -4116,8 +4116,7 @@ function fxBibStaticFallback($clef) {
'bib_v5_ops_empty' => ['fr' => 'Aucun événement à venir avec des dossards.', 'en' => 'No upcoming events with bibs.'],
'bib_v5_ops_due_empty' => ['fr' => '—', 'en' => '—'],
'bib_v5_ops_overdue' => ['fr' => 'Échéance dépassée', 'en' => 'Past due'],
'bib_v5_ops_done' => ['fr' => 'Fait', 'en' => 'Done'],
'bib_v5_ops_unauthorized' => ['fr' => 'Cette page est réservée aux gestionnaires de dossards MS1.', 'en' => 'This page is for MS1 bib managers only.'],
'bib_v5_ops_unauthorized' => ['fr' => 'Cette page est réservée aux gestionnaires de commande de dossards et puces MS1.', 'en' => 'This page is for MS1 bib and chip order managers only.'],
'bib_v5_cmd_sheet_dossards' => ['fr' => 'Commande dossards', 'en' => 'Bib order'],
'bib_v5_cmd_sheet_puces' => ['fr' => 'Commande puces', 'en' => 'Chip order'],
'bib_v5_cmd_excel_header_puce' => ['fr' => 'PUCE', 'en' => 'CHIP'],

View File

@ -519,8 +519,8 @@ function fxPromoteurHubStaticFallback($clef, $strLangParam = '')
$tab = array(
'promoteur_hub_section_gestion' => array('fr' => 'Gestion', 'en' => 'Management'),
'promoteur_hub_link_dashboard' => array('fr' => 'Tableau de bord V2', 'en' => 'V2 dashboard'),
'promoteur_hub_bib_ops_btn' => array('fr' => 'Gestionnaire de dossards', 'en' => 'Bib manager'),
'promoteur_hub_bib_ops_help' => array('fr' => 'Rapport global des jalons — temporaire, avant le CRM.', 'en' => 'Global milestone report — temporary, until CRM.'),
'promoteur_hub_bib_ops_btn' => array('fr' => 'Gestionnaire de commande de dossards et puces', 'en' => 'Bib and chip order manager'),
'promoteur_hub_bib_ops_help' => array('fr' => 'Rapport jalons et dates réelles — temporaire, avant le CRM.', 'en' => 'Milestone and actual-date report — temporary, until CRM.'),
'promoteur_hub_no_features' => array(
'fr' => 'Aucune fonctionnalité disponible avec vos droits actuels.',
'en' => 'No features available with your current permissions.',

View File

@ -7,7 +7,7 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.73.036'); // MSIN-4577chooser : chevron collapse toujours visible
define('_VERSION_CODE', '4.73.037'); // MSIN-4578ops : jalon + date réelle, en-tête lisible
define('_DATE_CODE', '2026-08-19');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');

View File

@ -51,10 +51,10 @@ INSERT INTO `inscriptions_eve_permissions`
`perm_grants_all`, `perm_tri`)
VALUES
('dossards.ops_global', 'outils_ms1', 'outil',
'Gestionnaire de dossards',
'Bib manager',
'Tableau de bord global des jalons dossards. Kit compte seulement — jamais un kit événement / promoteur.',
'Global bib milestone dashboard. Account kit only — never an event / promoter kit.',
'Gestionnaire de commande de dossards et puces',
'Bib and chip order manager',
'Tableau de bord global des jalons et dates réelles. Kit compte seulement — jamais un kit événement / promoteur.',
'Global bib/chip milestone dashboard with due and actual dates. Account kit only — never an event / promoter kit.',
2, 1, 0, 10)
ON DUPLICATE KEY UPDATE
`perm_group` = VALUES(`perm_group`),
@ -74,9 +74,9 @@ INSERT INTO `inscriptions_eve_roles`
`role_icone`, `role_systeme`, `role_actif`, `role_tri`,
`role_delegable`, `role_grants_all`, `role_scope`)
VALUES
('gestionnaire_dossards', 'Gestionnaire de dossards', 'Bib manager',
'Outils dossards hors superadmin : rapport global des jalons. Attribué à une personne, pas à un événement.',
'Bib tools outside superadmin: global milestone report. Assigned to a person, not an event.',
('gestionnaire_dossards', 'Gestionnaire de commande de dossards et puces', 'Bib and chip order manager',
'Outils commande dossards / puces hors superadmin : rapport jalons et dates réelles. Attribué à une personne, pas à un événement.',
'Bib/chip order tools outside superadmin: due and actual dates. Assigned to a person, not an event.',
'fa-hashtag', 1, 1, 200, 0, 0, 'compte')
ON DUPLICATE KEY UPDATE
`role_label_fr` = VALUES(`role_label_fr`),
@ -109,14 +109,14 @@ INSERT INTO info (
SELECT src.info_clef, src.info_langue, src.info_texte, src.info_aide, 'compte.php',
'MSIN-4578', 0, 1, '', '', '', NOW()
FROM (
SELECT 'promoteur_hub_bib_ops_btn' info_clef, 'fr' info_langue, 'Gestionnaire de dossards' info_texte, '' info_aide
UNION ALL SELECT 'promoteur_hub_bib_ops_btn', 'en', 'Bib manager', ''
UNION ALL SELECT 'promoteur_hub_bib_ops_help', 'fr', 'Rapport global des jalons — temporaire, avant le CRM.', ''
UNION ALL SELECT 'promoteur_hub_bib_ops_help', 'en', 'Global milestone report — temporary, until CRM.', ''
UNION ALL SELECT 'bib_v5_ops_page_title', 'fr', 'Gestionnaire de dossards', ''
UNION ALL SELECT 'bib_v5_ops_page_title', 'en', 'Bib manager', ''
UNION ALL SELECT 'bib_v5_ops_intro', 'fr', 'Événements à venir qui ont des séquences de dossards. Les dates sont les jalons saisis sur la commande.', ''
UNION ALL SELECT 'bib_v5_ops_intro', 'en', 'Upcoming events that have bib ranges. Dates are the milestones entered on the order.', ''
SELECT 'promoteur_hub_bib_ops_btn' info_clef, 'fr' info_langue, 'Gestionnaire de commande de dossards et puces' info_texte, '' info_aide
UNION ALL SELECT 'promoteur_hub_bib_ops_btn', 'en', 'Bib and chip order manager', ''
UNION ALL SELECT 'promoteur_hub_bib_ops_help', 'fr', 'Rapport jalons et dates réelles — temporaire, avant le CRM.', ''
UNION ALL SELECT 'promoteur_hub_bib_ops_help', 'en', 'Milestone and actual-date report — temporary, until CRM.', ''
UNION ALL SELECT 'bib_v5_ops_page_title', 'fr', 'Gestionnaire de commande de dossards et puces', ''
UNION ALL SELECT 'bib_v5_ops_page_title', 'en', 'Bib and chip order manager', ''
UNION ALL SELECT 'bib_v5_ops_intro', 'fr', 'Événements à venir qui ont des séquences de dossards. Pour chaque jalon : la date cible, puis la date réelle.', ''
UNION ALL SELECT 'bib_v5_ops_intro', 'en', 'Upcoming events that have bib ranges. For each milestone: the due date, then the actual date.', ''
UNION ALL SELECT 'bib_v5_ops_back', 'fr', 'Retour au tableau de bord', ''
UNION ALL SELECT 'bib_v5_ops_back', 'en', 'Back to dashboard', ''
UNION ALL SELECT 'bib_v5_ops_col_event', 'fr', 'Événement', ''
@ -133,8 +133,8 @@ FROM (
UNION ALL SELECT 'bib_v5_ops_overdue', 'en', 'Past due', ''
UNION ALL SELECT 'bib_v5_ops_done', 'fr', 'Fait', ''
UNION ALL SELECT 'bib_v5_ops_done', 'en', 'Done', ''
UNION ALL SELECT 'bib_v5_ops_unauthorized', 'fr', 'Cette page est réservée aux gestionnaires de dossards MS1.', ''
UNION ALL SELECT 'bib_v5_ops_unauthorized', 'en', 'This page is for MS1 bib managers only.', ''
UNION ALL SELECT 'bib_v5_ops_unauthorized', 'fr', 'Cette page est réservée aux gestionnaires de commande de dossards et puces MS1.', ''
UNION ALL SELECT 'bib_v5_ops_unauthorized', 'en', 'This page is for MS1 bib and chip order managers only.', ''
) src
WHERE NOT EXISTS (
SELECT 1 FROM info current_info
@ -142,3 +142,21 @@ WHERE NOT EXISTS (
AND current_info.info_langue = src.info_langue
AND current_info.info_prg = 'compte.php'
);
-- Relibellés si le INSERT a déjà passé (WHERE NOT EXISTS).
UPDATE info i
INNER JOIN (
SELECT 'promoteur_hub_bib_ops_btn' info_clef, 'fr' info_langue, 'Gestionnaire de commande de dossards et puces' info_texte
UNION ALL SELECT 'promoteur_hub_bib_ops_btn', 'en', 'Bib and chip order manager'
UNION ALL SELECT 'promoteur_hub_bib_ops_help', 'fr', 'Rapport jalons et dates réelles — temporaire, avant le CRM.'
UNION ALL SELECT 'promoteur_hub_bib_ops_help', 'en', 'Milestone and actual-date report — temporary, until CRM.'
UNION ALL SELECT 'bib_v5_ops_page_title', 'fr', 'Gestionnaire de commande de dossards et puces'
UNION ALL SELECT 'bib_v5_ops_page_title', 'en', 'Bib and chip order manager'
UNION ALL SELECT 'bib_v5_ops_intro', 'fr', 'Événements à venir qui ont des séquences de dossards. Pour chaque jalon : la date cible, puis la date réelle.'
UNION ALL SELECT 'bib_v5_ops_intro', 'en', 'Upcoming events that have bib ranges. For each milestone: the due date, then the actual date.'
UNION ALL SELECT 'bib_v5_ops_unauthorized', 'fr', 'Cette page est réservée aux gestionnaires de commande de dossards et puces MS1.'
UNION ALL SELECT 'bib_v5_ops_unauthorized', 'en', 'This page is for MS1 bib and chip order managers only.'
) src ON src.info_clef = i.info_clef
AND src.info_langue = i.info_langue
SET i.info_texte = src.info_texte
WHERE i.info_prg = 'compte.php';