257 lines
10 KiB
PHP
257 lines
10 KiB
PHP
<?php
|
||
/**
|
||
* MSIN-4578 — Tableau de bord temporaire gestionnaire de dossards (ops MS1).
|
||
* Pont avant CRM : kit compte « gestionnaire_dossards », pas un extra d’événement.
|
||
*/
|
||
|
||
if (!function_exists('fxBibOpsUserCanAccessGlobal')) {
|
||
|
||
/** Kit compte gestionnaire_dossards (personne). Pas de bypass super-admin. */
|
||
function fxBibOpsUserCanAccessGlobal() {
|
||
$intComId = (int)($_SESSION['com_id'] ?? 0);
|
||
return $intComId > 0
|
||
&& function_exists('fxEveAccesCanBibOpsGlobal')
|
||
&& fxEveAccesCanBibOpsGlobal($intComId);
|
||
}
|
||
|
||
function fxBibOpsUserCanAccessCommande($intEveId) {
|
||
$intEveId = (int)$intEveId;
|
||
if ($intEveId <= 0) {
|
||
return false;
|
||
}
|
||
if (function_exists('fxBibProductionUserCanManageEvent')
|
||
&& fxBibProductionUserCanManageEvent($intEveId)) {
|
||
return true;
|
||
}
|
||
return fxBibOpsUserCanAccessGlobal();
|
||
}
|
||
|
||
function fxBibOpsHubUrl($strLangue = 'fr') {
|
||
global $vDomaine;
|
||
return rtrim((string)$vDomaine, '/')
|
||
. (($strLangue === 'en') ? '/account/promoteur_hub' : '/compte/promoteur_hub');
|
||
}
|
||
|
||
/**
|
||
* Événements actifs à venir qui ont au moins une séquence de dossard.
|
||
* @return array<int, array<string, mixed>>
|
||
*/
|
||
function fxBibOpsLoadUpcomingBibEvents($strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$strLangue = ($strLangue === 'en') ? 'en' : 'fr';
|
||
$strAlt = ($strLangue === 'fr') ? 'en' : 'fr';
|
||
$tabOut = [];
|
||
|
||
$tabEvents = $objDatabase->fxGetResults(
|
||
"SELECT e.eve_id, e.eve_nom_fr, e.eve_nom_en,
|
||
e.eve_date_debut, e.eve_date_fin
|
||
FROM inscriptions_evenements e
|
||
WHERE e.eve_actif = 1
|
||
AND (
|
||
(e.eve_date_fin IS NOT NULL
|
||
AND e.eve_date_fin <> '0000-00-00'
|
||
AND e.eve_date_fin >= CURDATE())
|
||
OR ((e.eve_date_fin IS NULL OR e.eve_date_fin = '0000-00-00')
|
||
AND e.eve_date_debut IS NOT NULL
|
||
AND e.eve_date_debut <> '0000-00-00'
|
||
AND e.eve_date_debut >= CURDATE())
|
||
)
|
||
AND EXISTS (
|
||
SELECT 1
|
||
FROM inscriptions_epreuves ep
|
||
INNER JOIN inscriptions_epreuves_bib b ON b.epr_id = ep.epr_id
|
||
WHERE ep.eve_id = e.eve_id
|
||
AND ep.epr_actif = 1
|
||
)
|
||
ORDER BY e.eve_date_debut ASC, e.eve_nom_fr ASC"
|
||
);
|
||
if (!is_array($tabEvents)) {
|
||
return $tabOut;
|
||
}
|
||
|
||
$tabEveIds = [];
|
||
foreach ($tabEvents as $tabRow) {
|
||
$intEveId = (int)($tabRow['eve_id'] ?? 0);
|
||
if ($intEveId <= 0) {
|
||
continue;
|
||
}
|
||
$tabEveIds[] = $intEveId;
|
||
$strNom = trim((string)($tabRow['eve_nom_' . $strLangue] ?? ''));
|
||
if ($strNom === '') {
|
||
$strNom = trim((string)($tabRow['eve_nom_' . $strAlt] ?? ''));
|
||
}
|
||
$tabOut[$intEveId] = [
|
||
'eve_id' => $intEveId,
|
||
'nom' => $strNom,
|
||
'date_label' => fxBibOpsFormatEventDate($tabRow),
|
||
'milestones' => [],
|
||
];
|
||
if (function_exists('fxBibCommandeMilestoneKinds')) {
|
||
foreach (fxBibCommandeMilestoneKinds() as $strKind) {
|
||
$tabOut[$intEveId]['milestones'][$strKind] = [
|
||
'due' => null,
|
||
'done_at' => null,
|
||
];
|
||
}
|
||
}
|
||
}
|
||
|
||
if (empty($tabEveIds) || !function_exists('fxBibCommandeHasMilestoneTable')
|
||
|| !fxBibCommandeHasMilestoneTable()) {
|
||
return array_values($tabOut);
|
||
}
|
||
|
||
$strIds = implode(',', array_map('intval', $tabEveIds));
|
||
$tabMs = $objDatabase->fxGetResults(
|
||
"SELECT eve_id, bcm_kind, bcm_due, bcm_done_at
|
||
FROM inscriptions_bib_commande_milestones
|
||
WHERE eve_id IN ($strIds)"
|
||
);
|
||
if (!is_array($tabMs)) {
|
||
return array_values($tabOut);
|
||
}
|
||
foreach ($tabMs as $tabRow) {
|
||
$intEveId = (int)($tabRow['eve_id'] ?? 0);
|
||
$strKind = function_exists('fxBibCommandeNormalizeKind')
|
||
? fxBibCommandeNormalizeKind($tabRow['bcm_kind'] ?? '')
|
||
: '';
|
||
if ($intEveId <= 0 || $strKind === '' || !isset($tabOut[$intEveId])) {
|
||
continue;
|
||
}
|
||
$tabOut[$intEveId]['milestones'][$strKind] = [
|
||
'due' => ($tabRow['bcm_due'] ?? '') !== '' && $tabRow['bcm_due'] !== '0000-00-00'
|
||
? (string)$tabRow['bcm_due']
|
||
: null,
|
||
'done_at' => ($tabRow['bcm_done_at'] ?? '') !== '' && $tabRow['bcm_done_at'] !== '0000-00-00 00:00:00'
|
||
? (string)$tabRow['bcm_done_at']
|
||
: null,
|
||
];
|
||
}
|
||
|
||
return array_values($tabOut);
|
||
}
|
||
|
||
function fxBibOpsFormatEventDate(array $tabRow) {
|
||
$strDebut = trim((string)($tabRow['eve_date_debut'] ?? ''));
|
||
$strFin = trim((string)($tabRow['eve_date_fin'] ?? ''));
|
||
if ($strDebut === '' || strpos($strDebut, '0000-00-00') === 0) {
|
||
return '';
|
||
}
|
||
$strFmtDebut = substr($strDebut, 0, 10);
|
||
if ($strFin === '' || strpos($strFin, '0000-00-00') === 0 || substr($strFin, 0, 10) === $strFmtDebut) {
|
||
return $strFmtDebut;
|
||
}
|
||
return $strFmtDebut . ' — ' . substr($strFin, 0, 10);
|
||
}
|
||
|
||
function fxBibOpsDueIsOverdue($strDue, $strDoneAt) {
|
||
$strDue = trim((string)$strDue);
|
||
$strDoneAt = trim((string)$strDoneAt);
|
||
if ($strDue === '' || $strDoneAt !== '') {
|
||
return false;
|
||
}
|
||
$intTs = strtotime($strDue);
|
||
if ($intTs <= 0) {
|
||
return false;
|
||
}
|
||
return $intTs < strtotime(date('Y-m-d'));
|
||
}
|
||
|
||
/** Date seule (Y-m-d) pour le rapport ops — pas l’heure. */
|
||
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);
|
||
$tabKinds = function_exists('fxBibCommandeMilestoneKinds')
|
||
? fxBibCommandeMilestoneKinds()
|
||
: [];
|
||
$strEmptyDue = fxBibTexte('bib_v5_ops_due_empty', 0);
|
||
$strOverdue = fxBibTexte('bib_v5_ops_overdue', 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">';
|
||
$html .= '<div>';
|
||
$html .= '<h1>' . fxBibEsc(fxBibTexte('bib_v5_ops_page_title', 0)) . '</h1>';
|
||
$html .= '<p class="text-muted mb-0">' . fxBibEsc(fxBibTexte('bib_v5_ops_intro', 0)) . '</p>';
|
||
$html .= '</div>';
|
||
$html .= '<a class="btn btn-outline-secondary rounded-pill ml-auto" href="'
|
||
. fxBibEsc(fxBibOpsHubUrl($strLangue)) . '">'
|
||
. fxBibEsc(fxBibTexte('bib_v5_ops_back', 0)) . '</a>';
|
||
$html .= '</div>';
|
||
|
||
if (empty($tabEvents)) {
|
||
$html .= '<div class="alert alert-info">' . fxBibEsc(fxBibTexte('bib_v5_ops_empty', 0)) . '</div>';
|
||
$html .= '</div>';
|
||
return $html;
|
||
}
|
||
|
||
$html .= '<div class="table-responsive bib-ops-table-wrap">';
|
||
$html .= '<table class="table table-sm bib-ops-table">';
|
||
$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 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 .= '</tr></thead><tbody>';
|
||
|
||
foreach ($tabEvents as $tabEve) {
|
||
$intEveId = (int)$tabEve['eve_id'];
|
||
$strCmdUrl = function_exists('fxBibCommandePageUrl')
|
||
? fxBibCommandePageUrl($intEveId, $strLangue)
|
||
: '#';
|
||
$html .= '<tr>';
|
||
$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 = fxBibOpsFormatReportDate($tabMs['due'] ?? '');
|
||
$strDoneAt = fxBibOpsFormatReportDate($tabMs['done_at'] ?? '');
|
||
$blnOverdue = fxBibOpsDueIsOverdue($strDue, $strDoneAt);
|
||
$strDueClass = 'bib-ops-jalon';
|
||
if ($blnOverdue) {
|
||
$strDueClass .= ' is-overdue';
|
||
}
|
||
$html .= '<td class="' . $strDueClass . '"';
|
||
if ($blnOverdue) {
|
||
$html .= ' title="' . fxBibEsc($strOverdue) . '"';
|
||
}
|
||
$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="'
|
||
. fxBibEsc($strCmdUrl) . '">' . fxBibEsc($strOpen) . '</a></td>';
|
||
$html .= '</tr>';
|
||
}
|
||
|
||
$html .= '</tbody></table></div></div>';
|
||
return $html;
|
||
}
|
||
}
|