From 1ecc448df10065699fe4b95cfa776094553cf935 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 5 Aug 2026 17:30:29 -0400 Subject: [PATCH] =?UTF-8?q?MSIN-4568=20=E2=80=94=20Implement=20unlink=20fu?= =?UTF-8?q?nctionality=20for=20ChronoTrack=20events,=20allowing=20users=20?= =?UTF-8?q?to=20disconnect=20from=20the=20current=20event=20and=20select?= =?UTF-8?q?=20a=20new=20one.=20This=20includes=20updates=20to=20the=20UI?= =?UTF-8?q?=20for=20unlinking,=20backend=20logic=20for=20resetting=20confi?= =?UTF-8?q?gurations,=20and=20handling=20participant=20entries.=20Ensure?= =?UTF-8?q?=20safe=20unlinking=20without=20affecting=20existing=20entries?= =?UTF-8?q?=20in=20ChronoTrack.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/chronotrack_api/fx_chronotrack_admin.php | 43 ++++++++++- php/chronotrack_api/fx_chronotrack_config.php | 76 +++++++++++++++++++ superadm/ajax_chronotrack_api.php | 9 +++ 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/php/chronotrack_api/fx_chronotrack_admin.php b/php/chronotrack_api/fx_chronotrack_admin.php index bbc1619..16117b1 100644 --- a/php/chronotrack_api/fx_chronotrack_admin.php +++ b/php/chronotrack_api/fx_chronotrack_admin.php @@ -63,6 +63,9 @@ function fxChronotrackApiAdminRenderEventFormLinkedSummary($intEveId, $arrConfig echo '

'; echo '' . ' Ouvrir le tableau de bord (nouvelle fenêtre)'; + // MSIN-4568 — délier pour choisir un autre event CT + echo ' '; echo ''; } @@ -327,13 +330,22 @@ function fxChronotrackApiAdminRenderStatusActions($intEveId, $strStatus, $blnEve } if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_ACTIF) { echo 'Sync active'; - echo ''; + echo ''; } if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_FERME) { echo 'Fermé'; echo ''; } - echo ''; + echo ''; + // MSIN-4568 — vrai délier (≠ Terminer) pour changer d’event CT + if ($blnEventLinked) { + echo '
'; + echo '

Pour lier un autre événement ChronoTrack : déconnecter ' + . '(remet le choix CT ; les participants déjà envoyés restent dans l’ancien CT).

'; + echo ''; + } + echo ''; } function fxChronotrackApiAdminRenderRaceMapping($intEveId, $arrConfig, $strLangue, $blnClosed, $blnEventLinked = true) { @@ -894,6 +906,33 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed }, 'json'); }); + // MSIN-4568 — délier (confirm) puis recharger le sélecteur CT + $(document).on('click', '#ct_api_btn_unlink', function () { + var strConfirm = 'Êtes-vous sûr de vouloir déconnecter cet événement de ChronoTrack ?\n\n' + + 'Vous pourrez ensuite en choisir un autre.\n' + + 'Les participants déjà envoyés restent dans l’ancien événement ChronoTrack.\n' + + 'Le mapping et les liens techniques MS1 seront réinitialisés.'; + if (!window.confirm(strConfirm)) { + return; + } + var $btn = $(this); + $btn.prop('disabled', true); + $.post(strAjaxUrl, { a: 'unlink', eve_id: intEveId }, function (res) { + if (rejectIfSessionLost(res)) { + return; + } + if (!res || res.state !== 'ok') { + showMsg('error', (res && res.message) ? res.message : 'Erreur déconnexion'); + $btn.prop('disabled', false); + return; + } + window.location.reload(); + }, 'json').fail(function () { + showMsg('error', 'Erreur réseau'); + $btn.prop('disabled', false); + }); + }); + function loadRacesIntoSelects() { if (intLinkedCtEventId <= 0) { return; diff --git a/php/chronotrack_api/fx_chronotrack_config.php b/php/chronotrack_api/fx_chronotrack_config.php index 6a71cc3..f67f6f9 100644 --- a/php/chronotrack_api/fx_chronotrack_config.php +++ b/php/chronotrack_api/fx_chronotrack_config.php @@ -117,6 +117,82 @@ function fxChronotrackApiConfigSetStatus($intEveId, $strStatus, $intUsaId) { return array('state' => 'ok'); } +/** + * MSIN-4568 — délier MS1 ↔ ChronoTrack (pour relier un autre event CT). + * Reset safe : config, mapping, ct_entry_id participants, job push temp. + * Ne touche pas aux entries déjà créées côté ChronoTrack. + * + * @return array{state:string,message?:string,cleared_entry_ids?:int} + */ +function fxChronotrackApiConfigUnlink($intEveId, $intUsaId = 0) { + global $objDatabase; + + $intEveId = intval($intEveId); + $intUsaId = intval($intUsaId); + if ($intEveId <= 0) { + return array('state' => 'error', 'message' => 'eve_id manquant'); + } + + $arrExisting = fxChronotrackApiConfigGet($intEveId); + if ($arrExisting === null || intval($arrExisting['ct_event_id'] ?? 0) <= 0) { + return array('state' => 'error', 'message' => 'Aucun lien ChronoTrack pour cet événement'); + } + + $intOldCtEventId = intval($arrExisting['ct_event_id']); + $strOldName = trim((string)($arrExisting['ct_event_name'] ?? '')); + + // 1) Couper les IDs entry de l’ancien event CT (sinon PUT / conflits sur le prochain lien) + $sqlCountIds = "SELECT COUNT(*) AS n FROM resultats_participants" + . " WHERE eve_id = " . $intEveId + . " AND ct_entry_id IS NOT NULL"; + $arrCountIds = $objDatabase->fxGetRow($sqlCountIds); + $intCleared = intval($arrCountIds['n'] ?? 0); + + $sqlClearIds = "UPDATE resultats_participants SET ct_entry_id = NULL, par_maj = par_maj" + . " WHERE eve_id = " . $intEveId + . " AND ct_entry_id IS NOT NULL"; + if (!$objDatabase->fxQuery($sqlClearIds)) { + return array('state' => 'error', 'message' => 'Erreur SQL reset ct_entry_id'); + } + + // 2) Mapping épreuves (race IDs de l’ancien CT) + $sqlDelMap = "DELETE FROM api_chronotrack_race_map WHERE eve_id = " . $intEveId; + if (!$objDatabase->fxQuery($sqlDelMap)) { + return array('state' => 'error', 'message' => 'Erreur SQL suppression mapping'); + } + + // 3) Config lien / sync auto / last_push + $sqlDelCfg = "DELETE FROM api_chronotrack_config WHERE eve_id = " . $intEveId; + if (!$objDatabase->fxQuery($sqlDelCfg)) { + return array('state' => 'error', 'message' => 'Erreur SQL suppression lien'); + } + + // 4) Job push en cours (fichier temp) + if (function_exists('fxChronotrackApiSyncPushJobClear')) { + fxChronotrackApiSyncPushJobClear($intEveId); + } + + if (function_exists('fxChronotrackApiSyncLog')) { + fxChronotrackApiSyncLog( + $intEveId, + 0, + 'unlink', + 'ok', + 'Délié CT event #' . $intOldCtEventId + . ($strOldName !== '' ? (' « ' . $strOldName . ' »') : '') + . ' — ct_entry_id vidés=' . $intCleared + . ($intUsaId > 0 ? (' — usa_id=' . $intUsaId) : '') + ); + } + + return array( + 'state' => 'ok', + 'message' => 'Événement délié de ChronoTrack. Vous pouvez en sélectionner un autre.', + 'cleared_entry_ids' => $intCleared, + 'old_ct_event_id' => $intOldCtEventId, + ); +} + /** * MSIN-4328 — mémorise la fin d’un push réussi (référence pour par_maj). */ diff --git a/superadm/ajax_chronotrack_api.php b/superadm/ajax_chronotrack_api.php index 977517b..835dcfc 100644 --- a/superadm/ajax_chronotrack_api.php +++ b/superadm/ajax_chronotrack_api.php @@ -61,6 +61,15 @@ switch ($strAction) { $tabRetour = fxChronotrackApiConfigSetStatus($intEveId, $strStatus, $intUsaId); break; + case 'unlink': + // MSIN-4568 — délier pour pouvoir relier un autre event CT + if ($intEveId <= 0) { + $tabRetour = array('state' => 'error', 'message' => 'eve_id manquant'); + break; + } + $tabRetour = fxChronotrackApiConfigUnlink($intEveId, $intUsaId); + break; + case 'list_races': $intCtEventId = intval($_REQUEST['ct_event_id'] ?? 0); if ($intCtEventId <= 0 && $intEveId > 0) {