MSIN-4568 — Implement unlink functionality for ChronoTrack events, allowing users to disconnect from the current event and select a new one. This includes updates to the UI for unlinking, backend logic for resetting configurations, and handling participant entries. Ensure safe unlinking without affecting existing entries in ChronoTrack.

This commit is contained in:
2026-08-05 17:30:29 -04:00
parent 59d41c995f
commit 1ecc448df1
3 changed files with 126 additions and 2 deletions

View File

@ -63,6 +63,9 @@ function fxChronotrackApiAdminRenderEventFormLinkedSummary($intEveId, $arrConfig
echo '</p>';
echo '<a class="btn btn-primary" href="' . fxChronotrackApiAdminEsc($strHubUrl) . '" target="_blank" rel="noopener">'
. '<i class="fa fa-external-link" aria-hidden="true"></i>&nbsp;Ouvrir le tableau de bord (nouvelle fenêtre)</a>';
// MSIN-4568 — délier pour choisir un autre event CT
echo ' <button type="button" class="btn btn-outline-danger ml-2" id="ct_api_btn_unlink">'
. 'Déconnecter de ChronoTrack</button>';
echo '</div></div>';
}
@ -327,13 +330,22 @@ function fxChronotrackApiAdminRenderStatusActions($intEveId, $strStatus, $blnEve
}
if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_ACTIF) {
echo '<span class="badge badge-success align-self-center mr-2">Sync active</span>';
echo '<button type="button" class="btn btn-danger btn-sm ct-api-set-status" data-status="' . MSIN_API_CHRONOTRACK_SYNC_FERME . '">Terminer / Déconnecter</button>';
echo '<button type="button" class="btn btn-danger btn-sm ct-api-set-status" data-status="' . MSIN_API_CHRONOTRACK_SYNC_FERME . '">Terminer la course</button>';
}
if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_FERME) {
echo '<span class="badge badge-secondary align-self-center mr-2">Fermé</span>';
echo '<button type="button" class="btn btn-outline-primary btn-sm ct-api-set-status" data-status="' . MSIN_API_CHRONOTRACK_SYNC_LIE . '">Rouvrir (Lié)</button>';
}
echo '</div></div></div>';
echo '</div>';
// MSIN-4568 — vrai délier (≠ Terminer) pour changer devent CT
if ($blnEventLinked) {
echo '<hr class="my-3">';
echo '<p class="small text-muted mb-2">Pour lier un <strong>autre</strong> événement ChronoTrack : déconnecter '
. '(remet le choix CT ; les participants déjà envoyés restent dans lancien CT).</p>';
echo '<button type="button" class="btn btn-outline-danger btn-sm" id="ct_api_btn_unlink">'
. 'Déconnecter de ChronoTrack</button>';
}
echo '</div></div>';
}
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 lancien é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;

View File

@ -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 lancien 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 lancien 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 dun push réussi (référence pour par_maj).
*/

View File

@ -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) {