1550 lines
45 KiB
PHP
1550 lines
45 KiB
PHP
<?php
|
||
session_start();
|
||
|
||
// MSIN-4379 — Traductions toujours au nom de compte.php (jamais ajax_bib_range.php).
|
||
define('MS1_BIB_AJAX', true);
|
||
$_SERVER['PHP_SELF'] = '/compte.php';
|
||
$_SERVER['SCRIPT_NAME'] = '/compte.php';
|
||
|
||
require_once('php/inc_fonctions.php');
|
||
require_once('php/inc_fx_promoteur.php');
|
||
|
||
$strLangue = $_SESSION['lang'] ?? 'fr';
|
||
$reqLang = $_REQUEST['lang'] ?? $_REQUEST['lng'] ?? '';
|
||
if (!empty($reqLang) && in_array($reqLang, ['fr', 'en'], true)) {
|
||
$strLangue = $reqLang;
|
||
}
|
||
$vPage = 'compte.php';
|
||
$vtexte_page = obtenirTextepage($vPage, $strLangue, 2);
|
||
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
|
||
$action = $_REQUEST['action'] ?? '';
|
||
|
||
$arrBibAjaxActions = [
|
||
'create',
|
||
'delete',
|
||
'save',
|
||
'view',
|
||
'batch_analysis',
|
||
'refresh_ranges',
|
||
'refresh_ranges_data',
|
||
'batch_go',
|
||
'batch_apply',
|
||
'batch_apply_chunk',
|
||
'reset_preview',
|
||
'reset_apply',
|
||
'reset_all_apply',
|
||
'save_allow_inter_epr',
|
||
'save_team_mode',
|
||
'toggle_lock',
|
||
'save_auto_config',
|
||
'anomalies',
|
||
'batch_global_analysis',
|
||
'batch_global_simulate',
|
||
'batch_global_gen_analysis',
|
||
'batch_global_gen_simulate',
|
||
'batch_global_gen_create',
|
||
'batch_global_free_analysis',
|
||
'batch_global_free_simulate',
|
||
'batch_global_free_plan',
|
||
'batch_apply_free_chunk',
|
||
'global_batch_panel',
|
||
'dist_print_panel',
|
||
];
|
||
|
||
if ($action !== '' && in_array($action, $arrBibAjaxActions, true)) {
|
||
fxBibRequireAjaxAccess();
|
||
}
|
||
|
||
// =====================
|
||
// CREATE
|
||
// =====================
|
||
if ($action == 'create') {
|
||
|
||
$epr_id = intval($_REQUEST['epr_id'] ?? 0);
|
||
|
||
if ($epr_id > 0) {
|
||
|
||
// ⚠️ On ne crée PLUS en DB
|
||
|
||
// On récupère les ranges existants AVEC stats
|
||
$tabBibRanges = fxInfosBibRange($epr_id);
|
||
|
||
// 👉 On ajoute UNE ligne vide (UI seulement)
|
||
$tabBibRanges[] = [
|
||
'epr_bib_id' => 0, // ID temporaire
|
||
'epr_id' => $epr_id,
|
||
'epr_bib_start' => '',
|
||
'epr_bib_finish' => '',
|
||
'dernier_bib' => '',
|
||
'nb_utilises' => '',
|
||
'liste_trous' => '',
|
||
'liste_doublons' => ''
|
||
];
|
||
|
||
// MSIN-4446 — summary_html pour pastille « N séquence(s) » hors du conteneur.
|
||
echo json_encode(array_merge([
|
||
'success' => true,
|
||
'html' => renderBibRanges($tabBibRanges, $epr_id),
|
||
'error' => ''
|
||
], fxBibAssignRangesAjaxExtras($epr_id, $tabBibRanges)));
|
||
exit;
|
||
}
|
||
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
|
||
// =====================
|
||
// DELETE
|
||
// =====================
|
||
if ($action == 'delete') {
|
||
|
||
$id = intval($_REQUEST['id'] ?? 0);
|
||
|
||
if ($id > 0) {
|
||
|
||
$rowLock = $objDatabase->fxGetRow("
|
||
SELECT epr_bib_locked
|
||
FROM inscriptions_epreuves_bib
|
||
WHERE epr_bib_id = $id
|
||
");
|
||
|
||
if ($rowLock && (int)($rowLock['epr_bib_locked'] ?? 0) === 1) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_range_locked')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$range = fxInfosBibRange(0,$id);
|
||
|
||
$epr_id = $range[1]["epr_id"];
|
||
|
||
|
||
|
||
|
||
|
||
if (!$range) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_range_not_found')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
if ((int)$range[1]['nb_utilises'] > 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_delete_used')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
|
||
|
||
$sql = "
|
||
DELETE FROM inscriptions_epreuves_bib
|
||
WHERE epr_bib_id = $id
|
||
";
|
||
|
||
$objDatabase->fxQuery($sql);
|
||
|
||
$tabBibRanges = fxInfosBibRange($epr_id);
|
||
|
||
// MSIN-4446 — Mettre à jour la pastille après suppression (ex. « Aucune séquence »).
|
||
echo json_encode(array_merge([
|
||
'success' => true,
|
||
'html' => renderBibRanges($tabBibRanges, $epr_id),
|
||
'error' => ''
|
||
], fxBibAssignRangesAjaxExtras($epr_id, $tabBibRanges)));
|
||
exit;
|
||
}
|
||
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_id_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
// =====================
|
||
// SAVE
|
||
// =====================
|
||
if ($action == 'save') {
|
||
|
||
$id = intval($_REQUEST['id'] ?? 0);
|
||
$epr_id = intval($_REQUEST['epr_id'] ?? 0);
|
||
$start = intval($_REQUEST['start'] ?? 0);
|
||
$end = intval($_REQUEST['end'] ?? 0);
|
||
|
||
$is_new = ($id == 0);
|
||
|
||
// =====================
|
||
// VALIDATION 1 — epr_id
|
||
// =====================
|
||
if ($is_new && $epr_id <= 0) {
|
||
echo json_encode(['success' => false, 'message' => fxBibMsg('bib_v4_ajax_epr_invalid')]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// recherche eve_id
|
||
// =====================
|
||
$sqlGet = "SELECT eve_id FROM inscriptions_epreuves WHERE epr_id = $epr_id";
|
||
$eve_id = (int)$objDatabase->fxGetVar($sqlGet);
|
||
|
||
// =====================
|
||
// VALIDATION 2 — VALEURS NUMÉRIQUES
|
||
// =====================
|
||
if ($start <= 0 || $end <= 0) {
|
||
echo json_encode(['success' => false, 'message' => fxBibMsg('bib_v4_ajax_values_invalid')]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// VALIDATION 3 — LOGIQUE INTERVALLE
|
||
// =====================
|
||
if ($start > $end) {
|
||
echo json_encode(['success' => false, 'message' => fxBibMsg('bib_v4_ajax_start_gt_end')]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// RÉCUPÉRER epr_id + PROTÉGER LES DOSSARDS SI UPDATE
|
||
// =====================
|
||
if (!$is_new) {
|
||
|
||
$sqlGet = "SELECT epr_id, epr_bib_locked FROM inscriptions_epreuves_bib WHERE epr_bib_id = $id";
|
||
$rowRange = $objDatabase->fxGetRow($sqlGet);
|
||
|
||
if (!$rowRange || (int)($rowRange['epr_id'] ?? 0) <= 0) {
|
||
echo json_encode(['success' => false, 'message' => fxBibMsg('bib_v4_ajax_range_not_found')]);
|
||
exit;
|
||
}
|
||
|
||
if ((int)($rowRange['epr_bib_locked'] ?? 0) === 1) {
|
||
echo json_encode(['success' => false, 'message' => fxBibMsg('bib_v4_ajax_range_locked')]);
|
||
exit;
|
||
}
|
||
|
||
$epr_id = (int)$rowRange['epr_id'];
|
||
|
||
if ($epr_id <= 0) {
|
||
echo json_encode(['success' => false, 'message' => fxBibMsg('bib_v4_ajax_range_not_found')]);
|
||
exit;
|
||
}
|
||
|
||
$sqlBibNumRp = fxBibSqlNoBibUnsigned('rp.no_bib');
|
||
$sqlCheckOrphans = "
|
||
SELECT COUNT(*)
|
||
FROM resultats_participants rp
|
||
INNER JOIN inscriptions_epreuves_bib b
|
||
ON b.epr_bib_id = $id
|
||
WHERE rp.epr_id = b.epr_id
|
||
AND $sqlBibNumRp BETWEEN b.epr_bib_start AND b.epr_bib_finish
|
||
AND (
|
||
$sqlBibNumRp < $start
|
||
OR $sqlBibNumRp > $end
|
||
)
|
||
";
|
||
|
||
$nbOrphans = (int)$objDatabase->fxGetVar($sqlCheckOrphans);
|
||
|
||
if ($nbOrphans > 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_orphans')
|
||
]);
|
||
exit;
|
||
}
|
||
}
|
||
|
||
// =====================
|
||
// VALIDATION 4 — OVERLAP pas de double epreuves
|
||
// =====================
|
||
$tabOverlaps = fxBibGetOverlappingRanges($eve_id, $start, $end, $is_new ? 0 : $id, $epr_id);
|
||
|
||
if (!empty($tabOverlaps)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibFormatOverlapConflictMessage($tabOverlaps, $strLangue)
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// INSERT OU UPDATE
|
||
// =====================
|
||
if ($is_new) {
|
||
|
||
$sql = "
|
||
INSERT INTO inscriptions_epreuves_bib
|
||
(epr_id, epr_bib_start, epr_bib_finish, update_date, update_qui, eve_id)
|
||
VALUES
|
||
($epr_id, $start, $end, NOW(), 'admin', $eve_id)
|
||
";
|
||
|
||
} else {
|
||
|
||
$sql = "
|
||
UPDATE inscriptions_epreuves_bib
|
||
SET epr_bib_start = $start,
|
||
epr_bib_finish = $end,
|
||
update_date = NOW(),
|
||
eve_id = $eve_id
|
||
WHERE epr_bib_id = $id
|
||
";
|
||
}
|
||
|
||
$objDatabase->fxQuery($sql);
|
||
|
||
// =====================
|
||
// RELOAD HTML
|
||
// =====================
|
||
$tabBibRanges = fxInfosBibRange($epr_id);
|
||
|
||
// MSIN-4446 — Pastille résumé après création / maj séquence.
|
||
echo json_encode(array_merge([
|
||
'success' => true,
|
||
'html' => renderBibRanges($tabBibRanges, $epr_id)
|
||
], fxBibAssignRangesAjaxExtras($epr_id, $tabBibRanges)));
|
||
|
||
exit;
|
||
}
|
||
// =====================
|
||
// VIEW
|
||
// =====================
|
||
if ($action == 'view') {
|
||
|
||
$epr_id = intval($_REQUEST['epr_id'] ?? 0);
|
||
$range_id = intval($_REQUEST['range_id'] ?? 0);
|
||
|
||
if ($epr_id <= 0 || $range_id < 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_params_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// TEMPORAIRE : affichage simple pour test
|
||
$html = renderBibView($epr_id, $range_id, $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html
|
||
]);
|
||
exit;
|
||
|
||
|
||
}
|
||
// =====================
|
||
// ANALYSE BATCH
|
||
// =====================
|
||
if ($action == 'batch_analysis') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
|
||
if ($epr_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$infoBib = fxInfosBibEpreuve($epr_id);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'info' => $infoBib
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// MSIN-4424 — Réglage doublons inter-épreuves (événement)
|
||
// =====================
|
||
if ($action == 'save_allow_inter_epr') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$blnAllow = !empty($_POST['allow']) && (string)$_POST['allow'] !== '0';
|
||
|
||
if ($int_eve_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$result = fxBibSetEventAllowsInterEprDuplicates($int_eve_id, $blnAllow);
|
||
|
||
if (empty($result['success'])) {
|
||
echo json_encode($result);
|
||
exit;
|
||
}
|
||
|
||
$strLangueAnom = $_SESSION['lang'] ?? 'fr';
|
||
$tabAnomalies = fxBibCollectAnomalies($int_eve_id, $strLangueAnom);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'allow_inter_epr' => !empty($result['allow_inter_epr']) ? 1 : 0,
|
||
'anomalies_html' => renderBibAnomaliesPanel($int_eve_id, $strLangueAnom, $tabAnomalies),
|
||
'anomaly_count' => fxBibAnomalyTotalCount($tabAnomalies),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4436 — Panneau assignation globale (chargement différé à l'ouverture).
|
||
if ($action == 'global_batch_panel') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
|
||
if ($int_eve_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabEpreuves = $objDatabase->fxGetResults(
|
||
"SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = " . $int_eve_id . " AND epr_actif = 1 ORDER BY epr_id"
|
||
);
|
||
$tabBibAssignments = $objDatabase->fxGetResults(
|
||
"SELECT * FROM bib_assignements WHERE ba_actif = 1 ORDER BY ba_tri"
|
||
);
|
||
|
||
$html = renderBibGlobalBatchPanel($int_eve_id, $tabEpreuves, $tabBibAssignments, $strLangue);
|
||
|
||
if ($html === '') {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_unavailable'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html,
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4436 — Analyse batch global (épreuves solo, séquences par épreuve).
|
||
if ($action == 'batch_global_analysis') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$plans = json_decode($_POST['plans'] ?? '[]', true);
|
||
$tabPlans = fxBibParseGlobalBatchPlans($plans, $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $strSort1 === '' || empty($tabPlans)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$intParticipants = 0;
|
||
$intDispo = 0;
|
||
$intAssignable = 0;
|
||
$intManque = 0;
|
||
|
||
foreach ($tabPlans as $plan) {
|
||
$epr_id = (int)$plan['epr_id'];
|
||
$ranges = $plan['ranges'];
|
||
|
||
$participants = fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2);
|
||
$tabRangesInfos = fxInfosBibRange($epr_id);
|
||
$ids = array_map('intval', $ranges);
|
||
$tabRangesInfos = array_filter($tabRangesInfos, function ($r) use ($ids) {
|
||
return in_array((int)$r['epr_bib_id'], $ids, true);
|
||
});
|
||
|
||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id);
|
||
$intParticipants += (int)$summary['nb_participants'];
|
||
$intDispo += (int)$summary['nb_dispo'];
|
||
$intAssignable += (int)$summary['nb_assignable'];
|
||
$intManque += (int)$summary['nb_manque'];
|
||
}
|
||
|
||
$info = fxBibMsg(
|
||
'bib_v4_ajax_global_sim_summary',
|
||
count($tabPlans),
|
||
$intDispo,
|
||
$intParticipants,
|
||
$intAssignable,
|
||
$intManque
|
||
);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'info' => $info,
|
||
'stats' => [
|
||
'nb_epreuves' => count($tabPlans),
|
||
'nb_dispo' => $intDispo,
|
||
'nb_participants' => $intParticipants,
|
||
'nb_assignable' => $intAssignable,
|
||
'nb_manque' => $intManque,
|
||
],
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4436 — Simulation batch global.
|
||
if ($action == 'batch_global_simulate') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$plans = json_decode($_POST['plans'] ?? '[]', true);
|
||
$tabPlans = fxBibParseGlobalBatchPlans($plans, $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $strSort1 === '' || empty($tabPlans)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$htmlParts = [];
|
||
$intParticipants = 0;
|
||
$intDispo = 0;
|
||
$intAssignable = 0;
|
||
$intManque = 0;
|
||
|
||
foreach ($tabPlans as $plan) {
|
||
$epr_id = (int)$plan['epr_id'];
|
||
$ranges = $plan['ranges'];
|
||
|
||
$participants = fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2);
|
||
$tabRanges = fxGetRangesForBatchAssign($epr_id, $ranges);
|
||
$simu = fxProcessBatchAssignments($epr_id, $participants, $tabRanges, 'simulation');
|
||
|
||
$tabRangesInfos = fxInfosBibRange($epr_id);
|
||
$ids = array_map('intval', $ranges);
|
||
$tabRangesInfos = array_filter($tabRangesInfos, function ($r) use ($ids) {
|
||
return in_array((int)$r['epr_bib_id'], $ids, true);
|
||
});
|
||
|
||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id);
|
||
$intParticipants += (int)$summary['nb_participants'];
|
||
$intDispo += (int)$summary['nb_dispo'];
|
||
$intAssignable += (int)$summary['nb_assignable'];
|
||
$intManque += (int)$summary['nb_manque'];
|
||
|
||
$tabEpreuve = fxGetEpreuve($epr_id);
|
||
$strEprLabel = $tabEpreuve ? fxBibEpreuveDisplayName($tabEpreuve, $strLangue) : ('#' . $epr_id);
|
||
|
||
$htmlParts[] = '<div class="bib-global-sim-section">'
|
||
. '<h4 class="bib-global-sim-section__title">' . fxBibEsc($strEprLabel) . '</h4>'
|
||
. renderBibView(
|
||
$epr_id,
|
||
0,
|
||
$strLangue,
|
||
'simulation',
|
||
$simu,
|
||
fxBibTexte('bib_v4_ajax_title_simulation'),
|
||
fxBibMsg(
|
||
'bib_v4_ajax_sim_summary',
|
||
$summary['nb_dispo'],
|
||
$summary['nb_participants'],
|
||
$summary['nb_manque']
|
||
)
|
||
)
|
||
. '</div>';
|
||
}
|
||
|
||
$info = fxBibMsg(
|
||
'bib_v4_ajax_global_sim_summary',
|
||
count($tabPlans),
|
||
$intDispo,
|
||
$intParticipants,
|
||
$intAssignable,
|
||
$intManque
|
||
);
|
||
|
||
$html = fxBibWrapGlobalSimView($info, implode('', $htmlParts));
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html,
|
||
'info' => $info,
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4443 — Analyse batch global sans séquence (plages générées).
|
||
if ($action == 'batch_global_gen_analysis') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$intStartBib = (int)($_POST['start_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
|
||
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $intStartBib <= 0 || $strSort1 === '' || empty($tabEprIds)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_gen_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPlan = fxBibBuildGeneratedRangePlan($int_eve_id, $tabEprIds, $intStartBib, $strSort1, $strSort2);
|
||
$check = fxBibValidateGeneratedRangePlan($int_eve_id, $tabPlan, $strLangue);
|
||
|
||
if (!$check['success']) {
|
||
echo json_encode($check);
|
||
exit;
|
||
}
|
||
|
||
$tabStats = fxBibBuildGlobalBatchGeneratedAnalysisStats($tabPlan);
|
||
$intRangeStart = $intStartBib;
|
||
$intRangeEnd = $intStartBib - 1;
|
||
|
||
foreach ($tabPlan as $item) {
|
||
if (!empty($item['skip'])) {
|
||
continue;
|
||
}
|
||
if ($intRangeEnd < (int)$item['start']) {
|
||
$intRangeEnd = (int)$item['end'];
|
||
} else {
|
||
$intRangeEnd = (int)$item['end'];
|
||
}
|
||
}
|
||
|
||
$info = fxBibMsg(
|
||
'bib_v4_ajax_global_gen_analysis',
|
||
$tabStats['nb_epreuves'],
|
||
$intRangeStart,
|
||
$intRangeEnd,
|
||
$tabStats['nb_participants']
|
||
);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'info' => $info,
|
||
'stats' => $tabStats,
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4443 — Simulation batch global sans séquence.
|
||
if ($action == 'batch_global_gen_simulate') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$intStartBib = (int)($_POST['start_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
|
||
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $intStartBib <= 0 || $strSort1 === '' || empty($tabEprIds)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_gen_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPlan = fxBibBuildGeneratedRangePlan($int_eve_id, $tabEprIds, $intStartBib, $strSort1, $strSort2);
|
||
$result = fxBibSimulateGlobalBatchGenerated($int_eve_id, $tabPlan, $strSort1, $strSort2, $strLangue);
|
||
|
||
echo json_encode($result);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4443 — Création des séquences générées (phase 1 du GO).
|
||
if ($action == 'batch_global_gen_create') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$intStartBib = (int)($_POST['start_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
|
||
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $intStartBib <= 0 || $strSort1 === '' || empty($tabEprIds)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_gen_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPlan = fxBibBuildGeneratedRangePlan($int_eve_id, $tabEprIds, $intStartBib, $strSort1, $strSort2);
|
||
$check = fxBibValidateGeneratedRangePlan($int_eve_id, $tabPlan, $strLangue);
|
||
|
||
if (!$check['success']) {
|
||
echo json_encode($check);
|
||
exit;
|
||
}
|
||
|
||
$create = fxBibCreateGeneratedRanges($int_eve_id, $tabPlan, $strLangue);
|
||
|
||
if (!$create['success']) {
|
||
echo json_encode($create);
|
||
exit;
|
||
}
|
||
|
||
$tabStats = fxBibBuildGlobalBatchGeneratedAnalysisStats($tabPlan);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'plans' => $create['plans'],
|
||
'stats' => $tabStats,
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4445 — Analyse batch global libre (Début/Fin, sans séquence).
|
||
if ($action == 'batch_global_free_analysis') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$intStart = (int)($_POST['start_bib'] ?? 0);
|
||
$intEnd = (int)($_POST['end_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
|
||
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_free_plan_invalid'),
|
||
'duplicates' => ['has' => false, 'count' => 0, 'message' => ''],
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4445 — Doublons basés sur la plage entière (même si tri / épreuves incomplets).
|
||
$tabDupesOnly = fxBibFreeDuplicateRisk($int_eve_id, [], $intStart, $intEnd);
|
||
|
||
if ($strSort1 === '') {
|
||
$strSort1 = 'ba:2';
|
||
}
|
||
|
||
if (empty($tabEprIds)) {
|
||
echo json_encode([
|
||
'success' => true,
|
||
'info' => $tabDupesOnly['message'],
|
||
'stats' => ['nb_epreuves' => 0, 'nb_participants' => 0, 'nb_bibs' => 0],
|
||
'feedback' => fxBibFreeQtyFeedback($intEnd - $intStart + 1, 0),
|
||
'duplicates' => $tabDupesOnly,
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPlan = fxBibBuildFreeRangePlan($int_eve_id, $tabEprIds, $intStart, $intEnd, $strSort1, $strSort2);
|
||
$tabAnalysis = fxBibBuildGlobalBatchFreeAnalysis($int_eve_id, $tabPlan, $intStart, $intEnd);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'info' => $tabAnalysis['info'],
|
||
'stats' => $tabAnalysis['stats'],
|
||
'feedback' => $tabAnalysis['feedback'],
|
||
'duplicates' => $tabAnalysis['duplicates'],
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4445 — Simulation batch global libre.
|
||
if ($action == 'batch_global_free_simulate') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$intStart = (int)($_POST['start_bib'] ?? 0);
|
||
$intEnd = (int)($_POST['end_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
|
||
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart || $strSort1 === '' || empty($tabEprIds)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_free_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPlan = fxBibBuildFreeRangePlan($int_eve_id, $tabEprIds, $intStart, $intEnd, $strSort1, $strSort2);
|
||
$result = fxBibSimulateGlobalBatchFree(
|
||
$int_eve_id,
|
||
$tabPlan,
|
||
$intStart,
|
||
$intEnd,
|
||
$strSort1,
|
||
$strSort2,
|
||
$strLangue
|
||
);
|
||
|
||
echo json_encode($result);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4445 — Prépare les plans GO libres (aucune création de séquence).
|
||
if ($action == 'batch_global_free_plan') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? 0);
|
||
$intStart = (int)($_POST['start_bib'] ?? 0);
|
||
$intEnd = (int)($_POST['end_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$eprIds = json_decode($_POST['epr_ids'] ?? '[]', true);
|
||
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds(is_array($eprIds) ? $eprIds : [], $int_eve_id);
|
||
|
||
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart || $strSort1 === '' || empty($tabEprIds)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_free_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPlan = fxBibBuildFreeRangePlan($int_eve_id, $tabEprIds, $intStart, $intEnd, $strSort1, $strSort2);
|
||
$prepare = fxBibPrepareFreeRangePlans($int_eve_id, $tabPlan, $intStart, $intEnd, $strLangue);
|
||
|
||
echo json_encode($prepare);
|
||
exit;
|
||
}
|
||
|
||
if ($action == 'refresh_ranges') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? $_GET['epr_id'] ?? 0);
|
||
$mode = $_POST['mode'] ?? $_GET['mode'] ?? 'assign';
|
||
$blnLite = !empty($_POST['lite']) || !empty($_GET['lite']);
|
||
if ($epr_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabBibStats = fxInfosBibRange($epr_id, 0, $blnLite ? false : true);
|
||
|
||
// MSIN-4446 — Pastille résumé synchronisée avec le refresh des plages.
|
||
echo json_encode(array_merge([
|
||
'success' => true,
|
||
'html' => renderBibRanges($tabBibStats, $epr_id, $mode)
|
||
], fxBibAssignRangesAjaxExtras($epr_id, $tabBibStats)));
|
||
exit;
|
||
}
|
||
|
||
if ($action == 'refresh_ranges_data') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
|
||
if ($epr_id <= 0) {
|
||
echo json_encode(['success' => false]);
|
||
exit;
|
||
}
|
||
|
||
$tab = fxInfosBibRange($epr_id);
|
||
|
||
$out = [];
|
||
|
||
foreach ($tab as $r) {
|
||
$nb_total = $r['nb_total_range'] ?? 0;
|
||
$nb_used = (int)($r['nb_utilises'] ?? 0);
|
||
|
||
$out[] = [
|
||
'id' => (int)$r['epr_bib_id'],
|
||
'last' => (int)$r['dernier_bib'],
|
||
'used' => $nb_used,
|
||
'dispo' => $nb_total - $nb_used,
|
||
'trous' => $r['liste_trous'] ?? '',
|
||
'doublons' => $r['liste_doublons'] ?? ''
|
||
];
|
||
}
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'ranges' => $out
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// BATCH GO (DEBUG SEULEMENT)
|
||
// =====================
|
||
// Objectif :
|
||
// - recevoir les données du bouton GO
|
||
// - NE RIEN ÉCRIRE en DB
|
||
// - retourner les infos pour validation
|
||
|
||
if ($action == 'batch_go') {
|
||
|
||
// ID de l’épreuve
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
|
||
// Liste des ranges sélectionnés (JSON → array PHP)
|
||
$ranges = json_decode($_POST['ranges'] ?? '[]', true);
|
||
|
||
$lockCheck = fxBibAssertRangesUnlocked($epr_id, is_array($ranges) ? $ranges : []);
|
||
if (!$lockCheck['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_ajax_range_locked')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
fxBibSaveEpreuveBatchSort($epr_id, $strSort1, $strSort2);
|
||
|
||
$participants = fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2);
|
||
// =====================
|
||
// UTILISER LA FONCTION PROPRE
|
||
// =====================
|
||
$tabRanges = fxGetRangesForBatchAssign($epr_id, $ranges);
|
||
$tabRangesInfos = fxInfosBibRange($epr_id); // ← ICI
|
||
$ids = array_map('intval', $ranges);
|
||
$tabRangesInfos = array_filter($tabRangesInfos, function($r) use ($ids) {
|
||
return in_array((int)$r['epr_bib_id'], $ids);
|
||
});
|
||
|
||
$nextBib = fxGetNextAvailableBib($epr_id, $tabRanges);
|
||
$simu = fxProcessBatchAssignments($epr_id, $participants, $tabRanges, 'simulation');
|
||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id);
|
||
|
||
$info = fxBibMsg(
|
||
'bib_v4_ajax_sim_summary',
|
||
$summary['nb_dispo'],
|
||
$summary['nb_participants'],
|
||
$summary['nb_manque']
|
||
);
|
||
// =====================
|
||
// SIMULATION (temporaire simple)
|
||
// =====================
|
||
|
||
|
||
// =====================
|
||
// RENDER VIEW EN MODE SIMULATION
|
||
// =====================
|
||
$html = renderBibView(
|
||
$epr_id,
|
||
0,
|
||
$strLangue,
|
||
'simulation',
|
||
$simu,
|
||
fxBibTexte('bib_v4_ajax_title_simulation'),
|
||
$info
|
||
);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html,
|
||
// MSIN-4456 — diagnostic temporaire (Network) : vérifier sort_1=ba:5 pour Nom d'équipe
|
||
'sort_1' => $strSort1,
|
||
'sort_2' => $strSort2,
|
||
]);
|
||
|
||
exit;
|
||
|
||
|
||
|
||
}
|
||
|
||
if ($action == 'batch_apply') {
|
||
|
||
// =====================
|
||
// GO BATCH (EXÉCUTION RÉELLE)
|
||
// - Assigne les BIB en DB
|
||
// - Utilise fxProcessBatchAssignments en mode 'execute'
|
||
// - Affiche le résultat réel ($exec), pas de simulation
|
||
// =====================
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
$ranges = json_decode($_POST['ranges'] ?? '[]', true);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
|
||
$lockCheck = fxBibAssertRangesUnlocked($epr_id, is_array($ranges) ? $ranges : []);
|
||
if (!$lockCheck['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_ajax_range_locked')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
fxBibSaveEpreuveBatchSort($epr_id, $strSort1, $strSort2);
|
||
|
||
$participants = fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2);
|
||
$tabRanges = fxGetRangesForBatchAssign($epr_id, $ranges);
|
||
|
||
$exec = fxProcessBatchAssignments($epr_id, $participants, $tabRanges, 'execute');
|
||
|
||
$html = fxBibBuildBatchApplyHtml($epr_id, $exec, count($participants), $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html
|
||
]);
|
||
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4433 — GO batch par paquets : progression réelle + relecture BD entre paquets.
|
||
if ($action == 'batch_apply_chunk') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
$ranges = json_decode($_POST['ranges'] ?? '[]', true);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$intChunkSize = (int)($_POST['chunk_size'] ?? 50);
|
||
$intTotalInitial = (int)($_POST['total_initial'] ?? 0);
|
||
$blnBatchReset = ((int)($_POST['batch_reset'] ?? 0) === 1);
|
||
|
||
if ($intChunkSize < 1) {
|
||
$intChunkSize = 50;
|
||
}
|
||
if ($intChunkSize > 100) {
|
||
$intChunkSize = 100;
|
||
}
|
||
|
||
$lockCheck = fxBibAssertRangesUnlocked($epr_id, is_array($ranges) ? $ranges : []);
|
||
if (!$lockCheck['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_ajax_range_locked')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$strSessionKey = fxBibBatchExecSessionKey($epr_id);
|
||
|
||
if ($blnBatchReset) {
|
||
$_SESSION[$strSessionKey] = [];
|
||
fxBibSaveEpreuveBatchSort($epr_id, $strSort1, $strSort2);
|
||
} elseif (!isset($_SESSION[$strSessionKey]) || !is_array($_SESSION[$strSessionKey])) {
|
||
$_SESSION[$strSessionKey] = [];
|
||
}
|
||
|
||
$participants = fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2);
|
||
|
||
if ($intTotalInitial <= 0) {
|
||
$intTotalInitial = count($participants) + count($_SESSION[$strSessionKey]);
|
||
}
|
||
|
||
if (empty($participants)) {
|
||
$execAll = $_SESSION[$strSessionKey];
|
||
unset($_SESSION[$strSessionKey]);
|
||
|
||
$html = fxBibBuildBatchApplyHtml($epr_id, $execAll, $intTotalInitial, $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'complete' => true,
|
||
'total_initial' => $intTotalInitial,
|
||
'processed' => $intTotalInitial,
|
||
'assigned_total' => count($execAll),
|
||
'assigned_chunk' => 0,
|
||
'html' => $html
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabChunk = array_slice($participants, 0, $intChunkSize);
|
||
$tabRanges = fxGetRangesForBatchAssign($epr_id, $ranges);
|
||
$execChunk = fxProcessBatchAssignments($epr_id, $tabChunk, $tabRanges, 'execute');
|
||
|
||
$_SESSION[$strSessionKey] = array_merge($_SESSION[$strSessionKey], $execChunk);
|
||
|
||
$intRemaining = count(fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2));
|
||
$intProcessed = max(0, $intTotalInitial - $intRemaining);
|
||
$blnComplete = ($intRemaining === 0);
|
||
|
||
// MSIN-4433 — Dossards épuisés : clôturer si aucune progression sur ce paquet.
|
||
if (!$blnComplete && empty($execChunk)) {
|
||
$blnComplete = true;
|
||
}
|
||
|
||
$arrResponse = [
|
||
'success' => true,
|
||
'complete' => $blnComplete,
|
||
'total_initial' => $intTotalInitial,
|
||
'processed' => $intProcessed,
|
||
'assigned_total' => count($_SESSION[$strSessionKey]),
|
||
'assigned_chunk' => count($execChunk),
|
||
];
|
||
|
||
if ($blnComplete) {
|
||
$execAll = $_SESSION[$strSessionKey];
|
||
unset($_SESSION[$strSessionKey]);
|
||
$arrResponse['html'] = fxBibBuildBatchApplyHtml($epr_id, $execAll, $intTotalInitial, $strLangue);
|
||
}
|
||
|
||
echo json_encode($arrResponse);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4445 — GO batch par paquets avec plage virtuelle (sans séquence en BD).
|
||
if ($action == 'batch_apply_free_chunk') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
$intStart = (int)($_POST['start_bib'] ?? 0);
|
||
$intEnd = (int)($_POST['end_bib'] ?? 0);
|
||
list($strSort1, $strSort2) = fxBibParseBatchSortFromPost();
|
||
$intChunkSize = (int)($_POST['chunk_size'] ?? 50);
|
||
$intTotalInitial = (int)($_POST['total_initial'] ?? 0);
|
||
$blnBatchReset = ((int)($_POST['batch_reset'] ?? 0) === 1);
|
||
|
||
if ($intChunkSize < 1) {
|
||
$intChunkSize = 50;
|
||
}
|
||
if ($intChunkSize > 100) {
|
||
$intChunkSize = 100;
|
||
}
|
||
|
||
if ($epr_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_free_plan_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// Même filtre que le panneau : solo sans séquence.
|
||
$intEveId = (int)($_POST['eve_id'] ?? 0);
|
||
if ($intEveId > 0) {
|
||
$checkEpr = fxBibAssertSoloEpreuveForGlobalBatch($epr_id, $intEveId);
|
||
if (!$checkEpr['success']) {
|
||
echo json_encode($checkEpr);
|
||
exit;
|
||
}
|
||
if (fxBibEpreuveHasAnySequence($epr_id)) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_global_batch_gen_has_seq'),
|
||
]);
|
||
exit;
|
||
}
|
||
}
|
||
|
||
$strSessionKey = fxBibBatchExecSessionKey($epr_id) . '_free';
|
||
|
||
if ($blnBatchReset) {
|
||
$_SESSION[$strSessionKey] = [];
|
||
fxBibSaveEpreuveBatchSort($epr_id, $strSort1, $strSort2);
|
||
} elseif (!isset($_SESSION[$strSessionKey]) || !is_array($_SESSION[$strSessionKey])) {
|
||
$_SESSION[$strSessionKey] = [];
|
||
}
|
||
|
||
$participants = fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2);
|
||
|
||
if ($intTotalInitial <= 0) {
|
||
$intTotalInitial = count($participants) + count($_SESSION[$strSessionKey]);
|
||
}
|
||
|
||
if (empty($participants)) {
|
||
$execAll = $_SESSION[$strSessionKey];
|
||
unset($_SESSION[$strSessionKey]);
|
||
|
||
$html = fxBibBuildBatchApplyHtml($epr_id, $execAll, $intTotalInitial, $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'complete' => true,
|
||
'total_initial' => $intTotalInitial,
|
||
'processed' => $intTotalInitial,
|
||
'assigned_total' => count($execAll),
|
||
'assigned_chunk' => 0,
|
||
'html' => $html
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabChunk = array_slice($participants, 0, $intChunkSize);
|
||
$tabRanges = fxBibBuildVirtualRangesForPlan($intStart, $intEnd);
|
||
$execChunk = fxProcessBatchAssignments($epr_id, $tabChunk, $tabRanges, 'execute');
|
||
|
||
$_SESSION[$strSessionKey] = array_merge($_SESSION[$strSessionKey], $execChunk);
|
||
|
||
$intRemaining = count(fxGetParticipantsForBatchAssign($epr_id, $strSort1, $strSort2));
|
||
$intProcessed = max(0, $intTotalInitial - $intRemaining);
|
||
$blnComplete = ($intRemaining === 0);
|
||
|
||
if (!$blnComplete && empty($execChunk)) {
|
||
$blnComplete = true;
|
||
}
|
||
|
||
$arrResponse = [
|
||
'success' => true,
|
||
'complete' => $blnComplete,
|
||
'total_initial' => $intTotalInitial,
|
||
'processed' => $intProcessed,
|
||
'assigned_total' => count($_SESSION[$strSessionKey]),
|
||
'assigned_chunk' => count($execChunk),
|
||
];
|
||
|
||
if ($blnComplete) {
|
||
$execAll = $_SESSION[$strSessionKey];
|
||
unset($_SESSION[$strSessionKey]);
|
||
$arrResponse['html'] = fxBibBuildBatchApplyHtml($epr_id, $execAll, $intTotalInitial, $strLangue);
|
||
}
|
||
|
||
echo json_encode($arrResponse);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// RESET PREVIEW
|
||
// =====================
|
||
if ($action == 'reset_preview') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
|
||
$ranges = json_decode($_POST['ranges'] ?? '[]', true);
|
||
|
||
$lockCheck = fxBibAssertRangesUnlocked($epr_id, is_array($ranges) ? $ranges : []);
|
||
if (!$lockCheck['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_ajax_range_locked')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$participants = fxGetParticipantsForBatchReset($epr_id, $ranges);
|
||
|
||
$html = renderBibView(
|
||
$epr_id,
|
||
0,
|
||
$strLangue,
|
||
'reset',
|
||
$participants,
|
||
fxBibTexte('bib_v4_ajax_title_reset_preview'),
|
||
fxBibMsg('bib_v4_ajax_reset_preview_count', count($participants)),
|
||
'warning'
|
||
);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html
|
||
]);
|
||
|
||
exit;
|
||
}
|
||
// =====================
|
||
// RESET APPLY
|
||
// =====================
|
||
if ($action == 'reset_apply') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
|
||
$ranges = json_decode($_POST['ranges'] ?? '[]', true);
|
||
|
||
$lockCheck = fxBibAssertRangesUnlocked($epr_id, is_array($ranges) ? $ranges : []);
|
||
if (!$lockCheck['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_ajax_range_locked')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$participants = fxGetParticipantsForBatchReset($epr_id, $ranges);
|
||
|
||
$count = 0;
|
||
|
||
foreach ($participants as $p) {
|
||
|
||
$par_id = intval($p['par_id']);
|
||
|
||
if ($par_id <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$sql = "
|
||
UPDATE resultats_participants
|
||
SET no_bib = NULL
|
||
WHERE par_id = $par_id
|
||
AND is_cancelled = 0
|
||
";
|
||
|
||
$objDatabase->fxQuery($sql);
|
||
|
||
$count++;
|
||
}
|
||
|
||
// MSIN-4453 — Effacer aussi no_equipe (sinon le team# original reste et est réutilisé)
|
||
fxClearTeamNumbersAfterBibReset($epr_id, $participants);
|
||
|
||
$html = renderBibView(
|
||
$epr_id,
|
||
0,
|
||
$strLangue,
|
||
'reset',
|
||
$participants,
|
||
fxBibTexte('bib_v4_ajax_title_reset_done'),
|
||
fxBibMsg('bib_v4_ajax_reset_done_count', $count),
|
||
'success'
|
||
);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html
|
||
]);
|
||
|
||
exit;
|
||
}
|
||
// =====================
|
||
// RESET ALL ÉPREUVE
|
||
// =====================
|
||
if ($action == 'reset_all_apply') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
|
||
if ($epr_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_params_invalid'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$lockCheck = fxBibAssertEpreuveNoLockedRanges($epr_id);
|
||
if (!$lockCheck['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $lockCheck['message'] ?? fxBibMsg('bib_v4_js_reset_all_locked'),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$participants = fxGetParticipantsForEpreuveResetAll($epr_id);
|
||
|
||
$count = 0;
|
||
|
||
foreach ($participants as $p) {
|
||
|
||
$par_id = intval($p['par_id']);
|
||
|
||
if ($par_id <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$sql = "
|
||
UPDATE resultats_participants
|
||
SET no_bib = NULL
|
||
WHERE par_id = $par_id
|
||
AND is_cancelled = 0
|
||
";
|
||
|
||
$objDatabase->fxQuery($sql);
|
||
|
||
$count++;
|
||
}
|
||
|
||
// MSIN-4453 — Effacer aussi no_equipe (aligné reset legacy)
|
||
fxClearTeamNumbersAfterBibReset($epr_id);
|
||
|
||
$html = renderBibView(
|
||
$epr_id,
|
||
0,
|
||
$strLangue,
|
||
'reset',
|
||
$participants,
|
||
fxBibTexte('bib_v4_ajax_title_reset_all_done'),
|
||
fxBibMsg('bib_v4_ajax_reset_done_count', $count),
|
||
'success'
|
||
);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => $html,
|
||
]);
|
||
|
||
exit;
|
||
}
|
||
// =====================
|
||
// SAVE TEAM MODE
|
||
// =====================
|
||
if ($action == 'save_team_mode') {
|
||
|
||
$epr_id = intval($_REQUEST['epr_id'] ?? 0);
|
||
$team_mode = intval($_REQUEST['team_mode'] ?? 0);
|
||
|
||
if ($epr_id <= 0 || !in_array($team_mode, [1, 2, 3])) {
|
||
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_params_invalid')
|
||
]);
|
||
|
||
exit;
|
||
}
|
||
|
||
$sql = "
|
||
UPDATE inscriptions_epreuves
|
||
SET epr_bib_team_mode = $team_mode
|
||
WHERE epr_id = $epr_id
|
||
LIMIT 1
|
||
";
|
||
|
||
$objDatabase->fxQuery($sql);
|
||
|
||
echo json_encode([
|
||
'success' => true
|
||
]);
|
||
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4379 — Verrouillage séquence (cadenas ouvert/fermé)
|
||
if ($action == 'toggle_lock') {
|
||
|
||
$epr_bib_id = intval($_POST['epr_bib_id'] ?? 0);
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
$locked = intval($_POST['locked'] ?? 0) === 1;
|
||
|
||
$result = fxBibSetRangeLocked($epr_bib_id, $locked, $epr_id);
|
||
|
||
if (!$result['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $result['message'] ?? fxBibMsg('bib_v4_ajax_error')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$epr_id = (int)$result['epr_id'];
|
||
$tabBibStats = fxInfosBibRange($epr_id);
|
||
$tabExtras = fxBibAssignRangesAjaxExtras($epr_id, $tabBibStats);
|
||
|
||
echo json_encode(array_merge([
|
||
'success' => true,
|
||
'locked' => !empty($result['locked']),
|
||
'html' => renderBibRanges($tabBibStats, $epr_id, 'assign')
|
||
], $tabExtras));
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4379 — Étape 2
|
||
// Endpoint AJAX : sauvegarde ou désactivation de la config auto (epr_bib_auto).
|
||
// Paramètres : epr_id, active (0|1), ranges (JSON des epr_bib_id), csrf_token.
|
||
// Prochain tour : étape 6–7 (assignation réelle à l'achat, sans passer par cet endpoint).
|
||
if ($action == 'save_auto_config') {
|
||
|
||
$epr_id = intval($_POST['epr_id'] ?? 0);
|
||
$active = intval($_POST['active'] ?? 1) === 1;
|
||
$ranges = json_decode($_POST['ranges'] ?? '[]', true);
|
||
|
||
if ($epr_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$result = fxSaveBibAutoConfig($epr_id, is_array($ranges) ? $ranges : [], $active);
|
||
|
||
if (!$result['success']) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => $result['message'] ?? fxBibMsg('bib_v4_ajax_error')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabBibStats = fxInfosBibRange($epr_id);
|
||
$tabExtras = fxBibAssignRangesAjaxExtras($epr_id, $tabBibStats);
|
||
// Conserver le booléen métier de la config auto (prioritaire sur le recalcul).
|
||
$tabExtras['auto_active'] = !empty($result['auto_active']) ? 1 : 0;
|
||
$tabExtras['summary_html'] = fxBibAssignHeaderSummary(
|
||
(int)$tabExtras['seq_count'],
|
||
!empty($result['auto_active'])
|
||
);
|
||
|
||
echo json_encode(array_merge([
|
||
'success' => true,
|
||
'html' => renderBibRanges($tabBibStats, $epr_id, 'assign')
|
||
], $tabExtras));
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4379 — Dashboard anomalies (dossards en double, orphelins, etc.)
|
||
if ($action == 'anomalies') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? $_GET['eve_id'] ?? 0);
|
||
|
||
if ($int_eve_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabAnomalies = fxBibCollectAnomalies($int_eve_id, $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'count' => fxBibAnomalyTotalCount($tabAnomalies),
|
||
'html' => renderBibAnomaliesPanel($int_eve_id, $strLangue, $tabAnomalies),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4424 — Sommaire des quantités (toutes épreuves)
|
||
if ($action == 'qty_summary') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? $_GET['eve_id'] ?? 0);
|
||
|
||
if ($int_eve_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabSummary = fxBibCollectEventQtySummary($int_eve_id, $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'totals' => $tabSummary['totals'] ?? [],
|
||
'html' => renderBibQtySummaryPanel($int_eve_id, $strLangue, $tabSummary),
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// MSIN-4433 — Panneau impression PDF distribution dossards
|
||
if ($action == 'dist_print_panel') {
|
||
|
||
$int_eve_id = (int)($_POST['eve_id'] ?? $_GET['eve_id'] ?? 0);
|
||
|
||
if ($int_eve_id <= 0) {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_epr_invalid')
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
$tabPanel = fxBibCollectDistPrintPanelData($int_eve_id, $strLangue);
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'html' => renderBibDistPrintPanel($int_eve_id, $strLangue, $tabPanel),
|
||
'meta' => $tabPanel['meta'] ?? [],
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
// =====================
|
||
// ACTION INVALIDE
|
||
// =====================
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => fxBibMsg('bib_v4_ajax_action_invalid')
|
||
]);
|
||
exit; |