diff --git a/php/chronotrack_api/fx_chronotrack_admin.php b/php/chronotrack_api/fx_chronotrack_admin.php index 63ae9ea..bbc1619 100644 --- a/php/chronotrack_api/fx_chronotrack_admin.php +++ b/php/chronotrack_api/fx_chronotrack_admin.php @@ -1453,7 +1453,7 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed url: strAjaxUrl, type: 'POST', dataType: 'json', - timeout: 60000, + timeout: 120000, data: { a: 'sync_preview', eve_id: intEveId } }).done(function (res) { if (rejectIfSessionLost(res)) { @@ -1465,14 +1465,21 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed if (strStatus === 'abort') { return; } - var strMsg = (strStatus === 'timeout') - ? 'Délai dépassé — réessayez Actualiser.' - : 'Erreur réseau (preview).'; + var strMsg; + if (strStatus === 'timeout') { + strMsg = 'Délai dépassé (preview) — réessayez Actualiser.'; + } else if (strStatus === 'parsererror') { + strMsg = 'Réponse invalide (preview) — souvent un envoi encore en cours ou erreur PHP.'; + } else if (jqXHR && jqXHR.status) { + strMsg = 'Erreur preview HTTP ' + jqXHR.status + ' — réessayez Actualiser.'; + } else { + strMsg = 'Erreur réseau (preview). Si un envoi tourne, attendez la fin puis Actualiser.'; + } if ($status.length) { $status.removeClass('ct-api-push-status--ok ct-api-push-status--todo ct-api-push-status--loading') .html( '

' + escHtml(strMsg) + '

' - + '

Réessayez Actualiser.

' + + '

Les derniers compteurs affichés sont conservés.

' + '

' ); } @@ -1836,6 +1843,9 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed var blnFatal = false; blnPushRunning = true; + if (xhrPushPreview && xhrPushPreview.readyState !== 4) { + xhrPushPreview.abort(); + } $('#ct_api_btn_push, #ct_api_btn_push_full, #ct_api_btn_push_refresh, #ct_api_btn_ct_count, #ct_api_btn_logs').prop('disabled', true); function renderProgress(intDone, intTot, strExtra) { @@ -1879,7 +1889,13 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed } function pushChunk() { - renderProgress(intOffset, intTotal, 'lot en cours…'); + var intLot = Math.floor(intOffset / Math.max(1, intChunk)) + 1; + var intLots = Math.max(1, Math.ceil(intTotal / Math.max(1, intChunk))); + renderProgress( + intOffset, + intTotal, + 'lot ' + intLot + '/' + intLots + ' (POST ' + Math.min(intChunk, intTotal - intOffset) + ')…' + ); $.ajax({ url: strAjaxUrl, type: 'POST', @@ -1967,7 +1983,7 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed }); } - renderProgress(0, intTotal, 'préparation…'); + renderProgress(0, intTotal > 0 ? intTotal : 1, 'préparation MS1 (liste + job)…'); $.ajax({ url: strAjaxUrl, type: 'POST', diff --git a/php/chronotrack_api/fx_chronotrack_sync.php b/php/chronotrack_api/fx_chronotrack_sync.php index 933c0a7..afc58db 100644 --- a/php/chronotrack_api/fx_chronotrack_sync.php +++ b/php/chronotrack_api/fx_chronotrack_sync.php @@ -403,7 +403,7 @@ function fxChronotrackApiSyncGroupBlockedByType(array $tabBlocked) { /** * Classe les participants MS1 : transférables vs exclus (dossard, sexe, doublons MS1, mapping). */ -function fxChronotrackApiSyncClassifyParticipants(array $tabParticipants, array $arrRaceMap, $intCtEventId = 0) { +function fxChronotrackApiSyncClassifyParticipants(array $tabParticipants, array $arrRaceMap, $intCtEventId = 0, $blnBuildPayloads = true) { $tabCandidates = array(); $tabBlocked = array(); $tabBibCounts = array(); @@ -560,9 +560,12 @@ function fxChronotrackApiSyncClassifyParticipants(array $tabParticipants, array continue; } - $arrPayload = fxChronotrackApiSyncBuildEntryPayload($arrRow, $arrRaceMap, $intCtEventId); - if ($arrPayload === null) { - continue; + $arrPayload = null; + if ($blnBuildPayloads) { + $arrPayload = fxChronotrackApiSyncBuildEntryPayload($arrRow, $arrRaceMap, $intCtEventId); + if ($arrPayload === null) { + continue; + } } $tabTransferable[] = array( @@ -630,9 +633,12 @@ function fxChronotrackApiSyncClassifyParticipants(array $tabParticipants, array continue; } - $arrPayload = fxChronotrackApiSyncBuildEntryPayload($arrRep, $arrRaceMap, $intCtEventId); - if ($arrPayload === null) { - continue; + $arrPayload = null; + if ($blnBuildPayloads) { + $arrPayload = fxChronotrackApiSyncBuildEntryPayload($arrRep, $arrRaceMap, $intCtEventId); + if ($arrPayload === null) { + continue; + } } $tabTransferable[] = array( @@ -2018,7 +2024,8 @@ function fxChronotrackApiSyncBuildPreview($intEveId) { $intCtEventId = intval($arrConfig['ct_event_id']); $arrRaceMap = fxChronotrackApiRaceMapGetForEvent($intEveId); $tabParticipants = fxChronotrackApiSyncLoadMs1Participants($intEveId); - $arrClass = fxChronotrackApiSyncClassifyParticipants($tabParticipants, $arrRaceMap, $intCtEventId); + // MSIN-4328 — preview rapide : pas de build payloads / entry_notes (seulement compteurs + exclus) + $arrClass = fxChronotrackApiSyncClassifyParticipants($tabParticipants, $arrRaceMap, $intCtEventId, false); $intMs1Total = count($tabParticipants); $intTransferable = count($arrClass['transferable']); @@ -2036,7 +2043,7 @@ function fxChronotrackApiSyncBuildPreview($intEveId) { 'transferable' => $intTransferable, 'blocked_count' => $arrClass['blocked_count'], 'blocked_by_type' => $arrClass['blocked_by_type'], - 'blocked' => $arrClass['blocked'], + // Pas de liste plate « blocked » (doublon lourd) — l’UI utilise blocked_by_type 'eligible' => $intTransferable, 'skipped_no_race' => $arrClass['skipped_no_race'], 'skipped_no_external' => $arrClass['skipped_no_external'], @@ -2048,7 +2055,6 @@ function fxChronotrackApiSyncBuildPreview($intEveId) { 'anomaly_no_sex' => $arrClass['blocked_no_sex'], 'anomaly_duplicate_bib' => $arrClass['blocked_duplicate_bib'], 'duplicate_bib_numbers' => $arrClass['duplicate_bib_numbers'], - 'anomalies' => $arrClass['blocked'], 'ct_total' => null, 'ct_total_loaded' => false, 'already_in_ct' => null, @@ -2290,11 +2296,10 @@ function fxChronotrackApiSyncPushPrepare($intEveId, $arrOptions = array()) { $tabPending = fxChronotrackApiSyncFilterChangedSincePush($arrClass['transferable'], $strLastPushAt); } - // Plus de scan CT à la préparation : POST upsert (crée ou maj) sans entry_id. + // Garder entry_id en meta/job pour retry dossard ; l’envoi lot utilise POST upsert (pas PUT unitaire). $tabBatch = array(); $tabMeta = array(); foreach ($tabPending as $arrItem) { - // Garder entry_id si déjà lié CT → push chunk fera PUT (maj dossard fiable). $arrPayload = $arrItem['payload']; $strCtEntryId = preg_replace('/[^0-9]/', '', (string)($arrItem['row']['ct_entry_id'] ?? '')); if ($strCtEntryId !== '') { @@ -2443,34 +2448,17 @@ function fxChronotrackApiSyncPushEvent($intEveId, $arrOptions = array()) { $tabErrors = array(); $tabBibRetryChunk = array(); - // MSIN-4328 — entries liées (ct_entry_id) : PUT unitaire (+ clear bib si swap). - // Sans entry_id : POST lot (upsert). Ne plus stripper entry_id avant adaptive. + // MSIN-4328 — toujours POST en lot (upsert par external_id). + // Avant : PUT unitaire si ct_entry_id → ~100 appels/lot = 1–2 min figé à 0/N. + // entry_id reste sur le payload pour la 2e passe dossard ; retiré seulement à l’appel POST. $tabPostEntries = array(); $tabPostMeta = array(); foreach ($tabBatch as $intI => $arrPayload) { if (!is_array($arrPayload)) { continue; } - $strEntryId = trim((string)($arrPayload['entry_id'] ?? '')); - if ($strEntryId !== '') { - $arrOne = fxChronotrackApiSyncPushOneEntryWithBibConflictHandling( - $intCtEventId, - $arrPayload, - $tabMeta[$intI] ?? array('par_id' => 0, 'external_id' => ''), - $intEveId - ); - $intOk += intval($arrOne['ok'] ?? 0); - $intErr += intval($arrOne['err'] ?? 0); - $intPutOk += intval($arrOne['ok'] ?? 0); - if (!empty($arrOne['bib_retry']) && is_array($arrOne['bib_retry'])) { - foreach ($arrOne['bib_retry'] as $arrR) { - $tabBibRetryChunk[] = $arrR; - } - } - } else { - $tabPostEntries[] = $arrPayload; - $tabPostMeta[] = $tabMeta[$intI] ?? array('par_id' => 0, 'external_id' => ''); - } + $tabPostEntries[] = $arrPayload; + $tabPostMeta[] = $tabMeta[$intI] ?? array('par_id' => 0, 'external_id' => ''); } if (count($tabPostEntries) > 0) { diff --git a/superadm/ajax_chronotrack_api.php b/superadm/ajax_chronotrack_api.php index 3870b13..977517b 100644 --- a/superadm/ajax_chronotrack_api.php +++ b/superadm/ajax_chronotrack_api.php @@ -6,6 +6,10 @@ require_once dirname(__FILE__) . '/php/inc_functions.php'; require_once dirname(__FILE__) . '/../php/chronotrack_api/inc_bootstrap.php'; $intUsaId = fxSuperadmAjaxAuthOrJsonExit(); +// MSIN-4328 — libérer le verrou session : sinon un push long bloque Actualiser / preview (Erreur réseau). +if (session_status() === PHP_SESSION_ACTIVE) { + session_write_close(); +} $strAction = trim((string)($_REQUEST['a'] ?? '')); $intEveId = intval($_REQUEST['eve_id'] ?? 0); @@ -91,7 +95,7 @@ switch ($strAction) { $tabRetour = array('state' => 'error', 'message' => 'eve_id manquant'); break; } - set_time_limit(60); + set_time_limit(120); $tabRetour = fxChronotrackApiSyncBuildPreview($intEveId); break;