diff --git a/php/inc_fx_fiche_audit.php b/php/inc_fx_fiche_audit.php index e4b4fba..fa76c4d 100644 --- a/php/inc_fx_fiche_audit.php +++ b/php/inc_fx_fiche_audit.php @@ -315,6 +315,139 @@ function fxFicheAuditRecordChange( } } +/** + * MSIN-4464 — Dernière intervention seule (édition fiche, etc.), sans old→new. + */ +function fxFicheAuditRecordLastTouchOnly($intParId, $strTriggerField, $strSource = '', $intEveId = 0) +{ + global $objDatabase; + + $intParId = intval($intParId); + $strTriggerField = preg_replace('/[^a-z0-9_]/i', '', (string)$strTriggerField); + if ($strTriggerField === '') { + $strTriggerField = 'fiche'; + } + if ($intParId <= 0 || !isset($objDatabase) || !fxFicheAuditTablesReady()) { + return; + } + + $arrSettings = fxFicheAuditGetSettings(); + if (intval($arrSettings['track_last_touch']) !== 1) { + return; + } + + if ($intEveId <= 0) { + $intEveId = intval($objDatabase->fxGetVar( + 'SELECT eve_id FROM resultats_participants WHERE par_id = ' . $intParId . ' LIMIT 1' + )); + } + + $arrActor = fxFicheAuditResolveActor(); + fxFicheAuditInsertLogRow( + $intParId, + $intEveId, + 'last_touch', + '', + $strTriggerField, + $arrActor, + $strSource + ); + fxFicheAuditTrimField($intParId, 'last_touch', $arrSettings); +} + +/** + * Après annulation / rétablissement sur une commande (tous les par_id du pec). + */ +function fxFicheAuditRecordCancelRestoreForPec($intPecId, $strOld, $strNew, $strSource, $intEveId = 0) +{ + global $objDatabase; + + $intPecId = intval($intPecId); + if ($intPecId <= 0 || !isset($objDatabase) || !fxFicheAuditTablesReady()) { + return; + } + + $sql = 'SELECT par_id, eve_id FROM resultats_participants WHERE pec_id = ' . $intPecId; + $arrRows = $objDatabase->fxGetResults($sql); + if (!is_array($arrRows)) { + return; + } + + foreach ($arrRows as $row) { + if (!is_array($row) || empty($row['par_id'])) { + continue; + } + $intEveRow = intval($row['eve_id'] ?? 0); + if ($intEveRow <= 0) { + $intEveRow = intval($intEveId); + } + fxFicheAuditRecordChange( + intval($row['par_id']), + 'is_cancelled', + $strOld, + $strNew, + $strSource, + $intEveRow + ); + } +} + +/** + * Événements pour le sélecteur admin (actifs récents + ceux déjà dans les logs). + * + * @return array[] + */ +function fxFicheAuditAdminListEvents() +{ + global $objDatabase; + + if (!isset($objDatabase) || !fxFicheAuditTablesReady()) { + return array(); + } + + $sql = 'SELECT e.eve_id, e.eve_nom_fr, e.eve_date_debut,' + . ' (SELECT COUNT(*) FROM inscriptions_fiche_audit_log l WHERE l.eve_id = e.eve_id) AS fal_nb' + . ' FROM inscriptions_evenements e' + . ' WHERE e.eve_actif = 1' + . ' OR EXISTS (SELECT 1 FROM inscriptions_fiche_audit_log l2 WHERE l2.eve_id = e.eve_id)' + . ' ORDER BY e.eve_date_debut DESC, e.eve_id DESC' + . ' LIMIT 300'; + $arrRows = $objDatabase->fxGetResults($sql); + + return is_array($arrRows) ? $arrRows : array(); +} + +/** + * Derniers logs d'un événement (contrôle admin). + * + * @return array[] + */ +function fxFicheAuditAdminListRecentByEve($intEveId, $intLimit = 100) +{ + global $objDatabase; + + $intEveId = intval($intEveId); + $intLimit = intval($intLimit); + if ($intLimit !== 200) { + $intLimit = 100; + } + if ($intEveId <= 0 || !isset($objDatabase) || !fxFicheAuditTablesReady()) { + return array(); + } + + $sql = 'SELECT l.fal_id, l.par_id, l.eve_id, l.field_key, l.old_value, l.new_value,' + . ' l.changed_by_com_id, l.changed_by_label, l.source, l.created_at,' + . ' p.par_prenom, p.par_nom, p.no_bib' + . ' FROM inscriptions_fiche_audit_log l' + . ' LEFT JOIN resultats_participants p ON p.par_id = l.par_id' + . ' WHERE l.eve_id = ' . $intEveId + . ' ORDER BY l.created_at DESC, l.fal_id DESC' + . ' LIMIT ' . $intLimit; + $arrRows = $objDatabase->fxGetResults($sql); + + return is_array($arrRows) ? $arrRows : array(); +} + /** * @param array{com_id:int,label:string} $arrActor */ diff --git a/php/inc_fx_modifierinscriptions.php b/php/inc_fx_modifierinscriptions.php index 29d3fc8..c5a6bf1 100644 --- a/php/inc_fx_modifierinscriptions.php +++ b/php/inc_fx_modifierinscriptions.php @@ -310,6 +310,18 @@ function fxAnnulerRetablirInscription($tabEpreuve, $int_pec_id) { if (!$qryInscription || !$qryParticipants) { $tabRetour['state'] = 'error'; fxcreer_log("Erreur d'annulation d'inscription : " . $_SESSION['com_info']['com_courriel']); + } else { + // MSIN-4464 — audit annulation + if (!function_exists('fxFicheAuditRecordCancelRestoreForPec')) { + require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php'; + } + fxFicheAuditRecordCancelRestoreForPec( + intval($int_pec_id), + '0', + '1', + 'annuler', + intval($tabEpreuve['eve_id'] ?? 0) + ); } } else { $tabRetour['action'] = 'retablir'; @@ -327,6 +339,18 @@ function fxAnnulerRetablirInscription($tabEpreuve, $int_pec_id) { if (!$qryInscription || !$qryParticipants) { $tabRetour['state'] = 'error'; fxcreer_log("Erreur d'annulation d'inscription : " . $_SESSION['com_info']['com_courriel']); + } else { + // MSIN-4464 — audit rétablissement + if (!function_exists('fxFicheAuditRecordCancelRestoreForPec')) { + require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php'; + } + fxFicheAuditRecordCancelRestoreForPec( + intval($int_pec_id), + '1', + '0', + 'retablir', + intval($tabEpreuve['eve_id'] ?? 0) + ); } // ajuster qte epreuve diff --git a/php/inc_fx_panier.php b/php/inc_fx_panier.php index 5baa6a3..f5f592d 100644 --- a/php/inc_fx_panier.php +++ b/php/inc_fx_panier.php @@ -797,11 +797,26 @@ LEFT JOIN inscriptions_panier_epreuves ee on e.epr_id=ee.epr_id $intDiff = ($tabAncienneEpreuve['epr_nb_participants'] - $tabNouvelleEpreuve['epr_nb_participants']); for ($i = count($tabInscription); $i > $tabNouvelleEpreuve['epr_nb_participants']; $i--) { - $sqlUpdate = "UPDATE resultats_participants SET is_cancelled = 1, par_modification_promoteur = 1 WHERE par_id = " . intval($tabInscription[$i]['par_id']); + $intParCancel = intval($tabInscription[$i]['par_id']); + $sqlUpdate = "UPDATE resultats_participants SET is_cancelled = 1, par_modification_promoteur = 1 WHERE par_id = " . $intParCancel; $qryUpdate = $objDatabase->fxQuery($sqlUpdate); - if (!$qryUpdate) + if (!$qryUpdate) { fxcreer_log("Erreur lors du changemenet d'épreuve par le promoteur."); + } else { + // MSIN-4464 — participants surplus annulés au changement d'épreuve + if (!function_exists('fxFicheAuditRecordChange')) { + require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php'; + } + fxFicheAuditRecordChange( + $intParCancel, + 'is_cancelled', + '0', + '1', + 'changement_epreuve', + intval($tabInscription[$i]['eve_id'] ?? ($tabEvenement['general']['eve_id'] ?? 0)) + ); + } } $sqlUpdate = "UPDATE resultats_epreuves_commandees SET pec_equipe = " . $tabNouvelleEpreuve['epr_equipe'] . " WHERE pec_id_original = " . $intpec_id; @@ -921,6 +936,17 @@ LEFT JOIN inscriptions_panier_epreuves ee on e.epr_id=ee.epr_id if (!$qryUpdate) { fxcreer_log('Erreur dans la mise à jour des participants.(' . $tabInscription[1]['par_courriel'] . ')'); + } elseif ($strTableSqlPart === 'resultats_participants' && $strModMarker !== '') { + // MSIN-4464 — édition fiche promoteur : dernière intervention (pas le détail de chaque champ). + if (!function_exists('fxFicheAuditRecordLastTouchOnly')) { + require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php'; + } + fxFicheAuditRecordLastTouchOnly( + intval($intParId), + 'fiche', + 'fiche_edit', + intval($tabEvenement['general']['eve_id'] ?? 0) + ); } // catégorie if ($tabEvenement['general']['eve_categorie_auto'] == 1) { @@ -4094,8 +4120,15 @@ function fxMajEpreuvesCommandees($str_ancien_no_panier, $pec_id_old, $pec_id_new $sqlUpdate = "UPDATE resultats_participants SET is_cancelled = 1, par_modification_promoteur = 1, par_maj = '" . fxGetDateTime() . "' WHERE pec_id = " . intval($pec_id_old); $qryUpdateParticipants = $objDatabase->fxQuery($sqlUpdate); - if (!$qryUpdateEpreuve || !$qryUpdateParticipants) + if (!$qryUpdateEpreuve || !$qryUpdateParticipants) { fxcreer_log("Erreur de désactivation de l'ancienne épreuve lors d'un upgrade ou transfert."); + } else { + // MSIN-4464 — annulation suite upgrade / transfert + if (!function_exists('fxFicheAuditRecordCancelRestoreForPec')) { + require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php'; + } + fxFicheAuditRecordCancelRestoreForPec(intval($pec_id_old), '0', '1', 'transfert_upgrade', 0); + } } unset($_SESSION['ancien_no_panier']); diff --git a/php/inc_fx_promoteur.php b/php/inc_fx_promoteur.php index 736db25..41d4aa3 100644 --- a/php/inc_fx_promoteur.php +++ b/php/inc_fx_promoteur.php @@ -1789,6 +1789,11 @@ function fxShowBibNumbersTable($tab_epreuve, $strLangue, $intEveId = 0) { function fxSetBibNumbers($tab_data, $int_epr_id, $int_start, $int_finish, $int_type, $int_par_equipe, $str_action = '', $int_mode,$int_finish_dispo=999999) { global $strLangue, $objDatabase, $vDomaine; + // MSIN-4464 — audit dossards batch + if (!function_exists('fxFicheAuditRecordChange')) { + require_once dirname(__FILE__) . '/inc_fx_fiche_audit.php'; + } + if ($strLangue == 'fr') { $strPage = '/compte'; } else { @@ -1902,6 +1907,9 @@ function fxSetBibNumbers($tab_data, $int_epr_id, $int_start, $int_finish, $int_t for ($i = 1; $i <= count($tabInscriptions); $i++) { if ($tabInscriptions[$i]['rol_id'] != 3 && $tabInscriptions[$i]['rol_id'] != 4) { + $intParBatch = intval($tabInscriptions[$i]['par_id']); + $strOldBibBatch = (string)($tabInscriptions[$i]['no_bib'] ?? ''); + $strNewBibBatch = ($str_action == 'reset') ? '' : (string)($intNoBib + $intCtr); $sqlUpdate = "UPDATE resultats_participants "; if ($str_action == 'reset') { $sqlUpdate .= "SET no_bib = '', par_date_bib = null"; @@ -1919,8 +1927,18 @@ function fxSetBibNumbers($tab_data, $int_epr_id, $int_start, $int_finish, $int_t $sqlUpdate .= " WHERE par_id = " . $tabInscriptions[$i]['par_id'] . " AND is_cancelled = 0"; $qryUpdate = $objDatabase->fxQuery($sqlUpdate); - if (!$qryUpdate) + if (!$qryUpdate) { fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']); + } else { + fxFicheAuditRecordChange( + $intParBatch, + 'no_bib', + $strOldBibBatch, + $strNewBibBatch, + ($str_action == 'reset') ? 'bib_batch_reset' : 'bib_batch', + intval($tabInscriptions[$i]['eve_id'] ?? 0) + ); + } $sqlUpdate = "UPDATE resultats_epreuves_commandees SET no_equipe = '" . $objDatabase->fxEscape($intNoBib + $intCtr) . "' WHERE epr_id = " . intval($tabInscriptions[$i]['epr_id']) . " AND pec_id_original = " . $tabInscriptions[$i]['pec_id']; $qryUpdate = $objDatabase->fxQuery($sqlUpdate); @@ -1967,16 +1985,29 @@ function fxSetBibNumbers($tab_data, $int_epr_id, $int_start, $int_finish, $int_t } else{ $intNoBib = $strNumeroEquipe; } + $intParEqBatch = intval($tabEquipe[$j]['par_id']); + $strOldBibEq = (string)($tabEquipe[$j]['no_bib'] ?? ''); + $strNewBibEq = (string)$intNoBib; if($tabInscriptions[$i]['par_date_bib'] == null){ - $sqlUpdatePart = "UPDATE resultats_participants SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib). "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); + $sqlUpdatePart = "UPDATE resultats_participants SET par_date_bib = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib). "' WHERE par_id = " . $intParEqBatch; } else{ - $sqlUpdatePart = "UPDATE resultats_participants SET no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); + $sqlUpdatePart = "UPDATE resultats_participants SET no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . $intParEqBatch; // $sqlUpdatePart = "UPDATE resultats_participants SET par_maj = '" . fxGetDateTime() . "', no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); // $sqlUpdatePart = "UPDATE resultats_participants SET par_maj = '" . fxGetDateTime() . "', par_modification_promoteur = 1, no_bib = '" . $objDatabase->fxEscape($intNoBib) . "' WHERE par_id = " . intval($tabEquipe[$j]['par_id']); } $qryUpdatePart = $objDatabase->fxQuery($sqlUpdatePart); - if (!$qryUpdatePart) + if (!$qryUpdatePart) { fxcreer_log('Erreur lors de mise a jour du numero de dossard du participant ' . $tabInscriptions[$i]['par_id']); + } else { + fxFicheAuditRecordChange( + $intParEqBatch, + 'no_bib', + $strOldBibEq, + $strNewBibEq, + 'bib_batch', + intval($tabEquipe[$j]['eve_id'] ?? 0) + ); + } } } $intCtr++; diff --git a/superadm/fiche_audit.php b/superadm/fiche_audit.php index b0acec1..0e2b9c3 100644 --- a/superadm/fiche_audit.php +++ b/superadm/fiche_audit.php @@ -47,7 +47,10 @@ include('inc_header.php');
- L'enregistrement est actif pour statut, dossard et dossard remis (selon whitelist / dernière intervention). - L'affichage « ? » sur la fiche et le droit promoteur associé viennent dans une étape suivante. + Points branchés : statut, dossard manuel, dossard remis, annulation/rétablissement, édition fiche, + batch dossards, surplus changement d'épreuve, transfert/upgrade. + L'affichage « ? » sur la fiche et le droit promoteur associé viennent ensuite.
+ Affiche les dernières entrées enregistrées pour un événement — utile pour valider que ça logue bien. +
+ +Tables absentes — impossible d'afficher les logs.
+ + + +Aucun log pour cet événement.
+ +| Quand | +Participant | +Champ | +Avant | +Après | +Par | +Source | +
|---|---|---|---|---|---|---|
| = htmlspecialchars((string)($row['created_at'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | += htmlspecialchars($strNom, ENT_QUOTES, 'UTF-8') ?> | += htmlspecialchars($strField, ENT_QUOTES, 'UTF-8') ?> |
+ = htmlspecialchars((string)($row['old_value'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | += htmlspecialchars((string)($row['new_value'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | += htmlspecialchars((string)($row['changed_by_label'] ?? ''), ENT_QUOTES, 'UTF-8') ?> | += htmlspecialchars((string)($row['source'] ?? ''), ENT_QUOTES, 'UTF-8') ?> |
+