658 lines
19 KiB
PHP
658 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* MSIN-4443 / MSIN-4445 — Assignation globale solo sans séquence existante.
|
|
* Création automatique de plages puis assignation.
|
|
* Début obligatoire ; Fin/Qté optionnels (sinon taille = à assigner).
|
|
*/
|
|
|
|
/** True si l'épreuve a au moins une séquence enregistrée. */
|
|
function fxBibEpreuveHasAnySequence($epr_id) {
|
|
global $objDatabase;
|
|
|
|
$epr_id = (int)$epr_id;
|
|
if ($epr_id <= 0) {
|
|
return false;
|
|
}
|
|
|
|
$intCount = (int)$objDatabase->fxGetVar("
|
|
SELECT COUNT(*)
|
|
FROM inscriptions_epreuves_bib
|
|
WHERE epr_id = $epr_id
|
|
AND epr_bib_start IS NOT NULL
|
|
AND epr_bib_finish IS NOT NULL
|
|
");
|
|
|
|
return $intCount > 0;
|
|
}
|
|
|
|
/**
|
|
* Épreuves solo actives (avec ou sans séquence), triées par epr_id.
|
|
*
|
|
* @return array[] lignes inscriptions_epreuves
|
|
*/
|
|
function fxBibGetSoloEpreuves($int_eve_id, $tabEpreuves = null) {
|
|
global $objDatabase;
|
|
|
|
$int_eve_id = (int)$int_eve_id;
|
|
if ($int_eve_id <= 0) {
|
|
return [];
|
|
}
|
|
|
|
if (!is_array($tabEpreuves)) {
|
|
$tabEpreuves = $objDatabase->fxGetResults(
|
|
"SELECT * FROM inscriptions_epreuves e"
|
|
. " WHERE e.eve_id = $int_eve_id AND epr_actif = 1"
|
|
. " ORDER BY epr_id"
|
|
);
|
|
}
|
|
|
|
$out = [];
|
|
|
|
foreach ($tabEpreuves as $epr) {
|
|
if ((int)($epr['epr_equipe'] ?? 0) === 1) {
|
|
continue;
|
|
}
|
|
|
|
$out[] = $epr;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Épreuves solo sans aucune séquence, triées par epr_id (ordre page).
|
|
*
|
|
* @return array[] lignes inscriptions_epreuves
|
|
*/
|
|
function fxBibGetSoloEpreuvesWithoutSequence($int_eve_id, $tabEpreuves = null) {
|
|
$out = [];
|
|
|
|
foreach (fxBibGetSoloEpreuves($int_eve_id, $tabEpreuves) as $epr) {
|
|
if (fxBibEpreuveHasAnySequence((int)$epr['epr_id'])) {
|
|
continue;
|
|
}
|
|
|
|
$out[] = $epr;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/** Bloc 1 disponible : au moins 2 épreuves solo avec séquences sélectionnables. */
|
|
function fxBibGlobalBatchHasExistingBlock($int_eve_id, $tabEpreuves) {
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$intCount = 0;
|
|
|
|
foreach ($tabEpreuves as $epr) {
|
|
if ((int)($epr['epr_equipe'] ?? 0) === 1) {
|
|
continue;
|
|
}
|
|
|
|
if (empty(fxBibGetSelectableRangesForGlobalBatch((int)$epr['epr_id']))) {
|
|
continue;
|
|
}
|
|
|
|
$intCount++;
|
|
if ($intCount >= 2) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/** Bloc 2 disponible : au moins 1 épreuve solo sans séquence. */
|
|
function fxBibGlobalBatchHasGeneratedBlock($int_eve_id, $tabEpreuves) {
|
|
return count(fxBibGetSoloEpreuvesWithoutSequence($int_eve_id, $tabEpreuves)) >= 1;
|
|
}
|
|
|
|
/** Tuile / coquille assignation globale visible si l'un des blocs est utilisable. */
|
|
function fxBibGlobalBatchToolIsAvailable($int_eve_id, $tabEpreuves) {
|
|
return fxBibGlobalBatchHasExistingBlock($int_eve_id, $tabEpreuves)
|
|
|| fxBibGlobalBatchHasGeneratedBlock($int_eve_id, $tabEpreuves);
|
|
}
|
|
|
|
/**
|
|
* MSIN-4445 — Feedback quantité vs inscriptions à assigner (Fin/Qté optionnels).
|
|
*
|
|
* @return array{status:string, amount:int, qty:int, pending:int}
|
|
*/
|
|
function fxBibGeneratedQtyFeedback($intQty, $intPending) {
|
|
$intQty = (int)$intQty;
|
|
$intPending = (int)$intPending;
|
|
$intDiff = $intQty - $intPending;
|
|
|
|
if ($intDiff === 0) {
|
|
return [
|
|
'status' => 'juste',
|
|
'amount' => 0,
|
|
'qty' => $intQty,
|
|
'pending' => $intPending,
|
|
];
|
|
}
|
|
|
|
if ($intDiff > 0) {
|
|
return [
|
|
'status' => 'supplementaire',
|
|
'amount' => $intDiff,
|
|
'qty' => $intQty,
|
|
'pending' => $intPending,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'status' => 'manquante',
|
|
'amount' => abs($intDiff),
|
|
'qty' => $intQty,
|
|
'pending' => $intPending,
|
|
];
|
|
}
|
|
|
|
/** Libellé Info pour le feedback quantité (réutilise les clés MSIN-4445). */
|
|
function fxBibGeneratedQtyFeedbackMessage(array $tabFeedback) {
|
|
$strStatus = $tabFeedback['status'] ?? '';
|
|
$intAmount = (int)($tabFeedback['amount'] ?? 0);
|
|
|
|
if ($strStatus === 'juste') {
|
|
return fxBibMsg('bib_v4_global_batch_free_qty_juste');
|
|
}
|
|
|
|
if ($strStatus === 'supplementaire') {
|
|
return fxBibMsg('bib_v4_global_batch_free_qty_supplementaire', $intAmount);
|
|
}
|
|
|
|
if ($strStatus === 'manquante') {
|
|
return fxBibMsg('bib_v4_global_batch_free_qty_manquante', $intAmount);
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* MSIN-4445 — Nombre de dossards déjà assignés dans [start, end] pour l'événement.
|
|
*/
|
|
function fxBibCountAssignedBibsInRange($int_eve_id, $intStart, $intEnd) {
|
|
global $objDatabase;
|
|
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$intStart = (int)$intStart;
|
|
$intEnd = (int)$intEnd;
|
|
|
|
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
|
|
return 0;
|
|
}
|
|
|
|
$sqlBib = fxBibSqlNoBibUnsigned('p.no_bib');
|
|
|
|
return (int)$objDatabase->fxGetVar("
|
|
SELECT COUNT(DISTINCT $sqlBib)
|
|
FROM resultats_participants p
|
|
INNER JOIN inscriptions_epreuves e ON e.epr_id = p.epr_id
|
|
WHERE e.eve_id = $int_eve_id
|
|
AND IFNULL(p.is_cancelled, 0) = 0
|
|
AND p.no_bib IS NOT NULL
|
|
AND TRIM(p.no_bib) <> ''
|
|
AND $sqlBib BETWEEN $intStart AND $intEnd
|
|
");
|
|
}
|
|
|
|
/**
|
|
* Avertit si des dossards de la plage sont déjà portés, ou si une séquence chevauche.
|
|
*
|
|
* @return array{has:bool, count:int, message:string}
|
|
*/
|
|
function fxBibGeneratedDuplicateRisk($int_eve_id, $tabPlan, $intStart = 0, $intEnd = 0) {
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$intStart = (int)$intStart;
|
|
$intEnd = (int)$intEnd;
|
|
|
|
if ($intStart <= 0 || $intEnd < $intStart) {
|
|
foreach ((array)$tabPlan as $item) {
|
|
if (!empty($item['skip'])) {
|
|
continue;
|
|
}
|
|
$intItemStart = (int)($item['start'] ?? 0);
|
|
$intItemEnd = (int)($item['end'] ?? 0);
|
|
if ($intItemStart <= 0 || $intItemEnd < $intItemStart) {
|
|
continue;
|
|
}
|
|
if ($intStart <= 0 || $intItemStart < $intStart) {
|
|
$intStart = $intItemStart;
|
|
}
|
|
if ($intItemEnd > $intEnd) {
|
|
$intEnd = $intItemEnd;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($int_eve_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
|
|
return ['has' => false, 'count' => 0, 'message' => ''];
|
|
}
|
|
|
|
$intCount = fxBibCountAssignedBibsInRange($int_eve_id, $intStart, $intEnd);
|
|
$tabOverlaps = fxBibGetOverlappingRanges($int_eve_id, $intStart, $intEnd, 0, 0);
|
|
$intOverlapSeq = is_array($tabOverlaps) ? count($tabOverlaps) : 0;
|
|
|
|
if ($intCount <= 0 && $intOverlapSeq <= 0) {
|
|
return ['has' => false, 'count' => 0, 'message' => ''];
|
|
}
|
|
|
|
return [
|
|
'has' => true,
|
|
'count' => max($intCount, $intOverlapSeq),
|
|
'message' => fxBibMsg('bib_v4_global_batch_free_dupes_warn'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Valide et ordonne les epr_id du bloc généré (solo, sans séquence, ordre epr_id).
|
|
*
|
|
* @return int[]
|
|
*/
|
|
function fxBibParseGlobalBatchGeneratedEprIds($eprIds, $int_eve_id) {
|
|
if (!is_array($eprIds)) {
|
|
return [];
|
|
}
|
|
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$tabWanted = [];
|
|
|
|
foreach ($eprIds as $epr_id) {
|
|
$epr_id = (int)$epr_id;
|
|
if ($epr_id <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$check = fxBibAssertSoloEpreuveForGlobalBatch($epr_id, $int_eve_id);
|
|
if (!$check['success']) {
|
|
continue;
|
|
}
|
|
|
|
if (fxBibEpreuveHasAnySequence($epr_id)) {
|
|
continue;
|
|
}
|
|
|
|
$tabWanted[$epr_id] = true;
|
|
}
|
|
|
|
if (empty($tabWanted)) {
|
|
return [];
|
|
}
|
|
|
|
$tabIds = array_keys($tabWanted);
|
|
sort($tabIds, SORT_NUMERIC);
|
|
|
|
return $tabIds;
|
|
}
|
|
|
|
/**
|
|
* Plan de plages générées, enchaînement par epr_id.
|
|
* - Sans Fin ($intEndBib <= 0) : taille = à assigner (comportement historique).
|
|
* - Avec Fin/Qté : plage bornée ; le surplus va sur la dernière épreuve (impression d'avance).
|
|
*
|
|
* @return array[] [{epr_id, start, end, nb_pending, skip}]
|
|
*/
|
|
function fxBibBuildGeneratedRangePlan($int_eve_id, $tabEprIds, $intStartBib, $strSort1, $strSort2 = '', $intEndBib = 0) {
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$intStartBib = (int)$intStartBib;
|
|
$intEndBib = (int)$intEndBib;
|
|
$tabEprIds = fxBibParseGlobalBatchGeneratedEprIds($tabEprIds, $int_eve_id);
|
|
$blnBounded = ($intEndBib > 0 && $intEndBib >= $intStartBib);
|
|
$intCursor = $intStartBib;
|
|
$tabPlan = [];
|
|
$tabSorts = is_array($strSort1)
|
|
? fxBibNormalizeSortKeysList($strSort1)
|
|
: fxBibNormalizeSortKeysList([$strSort1, $strSort2]);
|
|
|
|
foreach ($tabEprIds as $epr_id) {
|
|
$participants = fxGetParticipantsForBatchAssign($epr_id, $tabSorts);
|
|
$intPending = count($participants);
|
|
|
|
if ($intPending <= 0) {
|
|
$tabPlan[] = [
|
|
'epr_id' => $epr_id,
|
|
'start' => 0,
|
|
'end' => 0,
|
|
'nb_pending' => 0,
|
|
'skip' => true,
|
|
];
|
|
continue;
|
|
}
|
|
|
|
if ($blnBounded) {
|
|
$intRemaining = $intEndBib - $intCursor + 1;
|
|
if ($intRemaining <= 0) {
|
|
$tabPlan[] = [
|
|
'epr_id' => $epr_id,
|
|
'start' => 0,
|
|
'end' => 0,
|
|
'nb_pending' => $intPending,
|
|
'skip' => true,
|
|
];
|
|
continue;
|
|
}
|
|
|
|
$intTake = min($intPending, $intRemaining);
|
|
$intStart = $intCursor;
|
|
$intEnd = $intCursor + $intTake - 1;
|
|
} else {
|
|
$intStart = $intCursor;
|
|
$intEnd = $intCursor + $intPending - 1;
|
|
}
|
|
|
|
$tabPlan[] = [
|
|
'epr_id' => $epr_id,
|
|
'start' => $intStart,
|
|
'end' => $intEnd,
|
|
'nb_pending' => $intPending,
|
|
'skip' => false,
|
|
];
|
|
|
|
$intCursor = $intEnd + 1;
|
|
}
|
|
|
|
// MSIN-4445 — Marge Fin/Qté : étendre la dernière séquence jusqu'à Fin (blancs imprimables).
|
|
if ($blnBounded) {
|
|
$intLastIdx = -1;
|
|
foreach ($tabPlan as $i => $item) {
|
|
if (empty($item['skip'])) {
|
|
$intLastIdx = $i;
|
|
}
|
|
}
|
|
if ($intLastIdx >= 0 && (int)$tabPlan[$intLastIdx]['end'] < $intEndBib) {
|
|
$tabPlan[$intLastIdx]['end'] = $intEndBib;
|
|
}
|
|
}
|
|
|
|
return $tabPlan;
|
|
}
|
|
|
|
/** Plages virtuelles pour simulation (même format que fxGetRangesForBatchAssign). */
|
|
function fxBibBuildVirtualRangesForPlan($intStart, $intEnd) {
|
|
$intStart = (int)$intStart;
|
|
$intEnd = (int)$intEnd;
|
|
|
|
if ($intStart <= 0 || $intEnd < $intStart) {
|
|
return [];
|
|
}
|
|
|
|
return [[
|
|
'id' => 0,
|
|
'start' => $intStart,
|
|
'end' => $intEnd,
|
|
]];
|
|
}
|
|
|
|
/**
|
|
* Valide le plan généré (chevauchements, épreuves sans séquence, au moins un à assigner).
|
|
*/
|
|
function fxBibValidateGeneratedRangePlan($int_eve_id, $tabPlan, $strLangue = 'fr') {
|
|
$int_eve_id = (int)$int_eve_id;
|
|
|
|
if (!is_array($tabPlan) || empty($tabPlan)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_plan_invalid'),
|
|
];
|
|
}
|
|
|
|
$blnHasAssignable = false;
|
|
|
|
foreach ($tabPlan as $item) {
|
|
if (!empty($item['skip'])) {
|
|
continue;
|
|
}
|
|
|
|
$blnHasAssignable = true;
|
|
$epr_id = (int)($item['epr_id'] ?? 0);
|
|
$intStart = (int)($item['start'] ?? 0);
|
|
$intEnd = (int)($item['end'] ?? 0);
|
|
|
|
if ($epr_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_plan_invalid'),
|
|
];
|
|
}
|
|
|
|
if (fxBibEpreuveHasAnySequence($epr_id)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_has_seq'),
|
|
];
|
|
}
|
|
|
|
$tabOverlaps = fxBibGetOverlappingRanges($int_eve_id, $intStart, $intEnd, 0, $epr_id);
|
|
if (!empty($tabOverlaps)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibFormatOverlapConflictMessage($tabOverlaps, $strLangue),
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!$blnHasAssignable) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_no_pending'),
|
|
];
|
|
}
|
|
|
|
return ['success' => true];
|
|
}
|
|
|
|
/**
|
|
* Crée les séquences en BD pour le plan validé.
|
|
*
|
|
* @return array{success:bool, message?:string, plans?:array}
|
|
*/
|
|
function fxBibCreateGeneratedRanges($int_eve_id, $tabPlan, $strLangue = 'fr') {
|
|
global $objDatabase;
|
|
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$tabCreated = [];
|
|
|
|
if (fxBibProductionEventIsLocked($int_eve_id)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v5_production_locked_error'),
|
|
];
|
|
}
|
|
|
|
foreach ($tabPlan as $item) {
|
|
if (!empty($item['skip'])) {
|
|
continue;
|
|
}
|
|
|
|
$epr_id = (int)($item['epr_id'] ?? 0);
|
|
$intStart = (int)($item['start'] ?? 0);
|
|
$intEnd = (int)($item['end'] ?? 0);
|
|
|
|
if ($epr_id <= 0 || $intStart <= 0 || $intEnd < $intStart) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_plan_invalid'),
|
|
];
|
|
}
|
|
|
|
if (fxBibEpreuveHasAnySequence($epr_id)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_has_seq'),
|
|
];
|
|
}
|
|
|
|
$tabOverlaps = fxBibGetOverlappingRanges($int_eve_id, $intStart, $intEnd, 0, $epr_id);
|
|
if (!empty($tabOverlaps)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibFormatOverlapConflictMessage($tabOverlaps, $strLangue),
|
|
];
|
|
}
|
|
|
|
// MSIN-4443 — Création séquence : vérifier INSERT + last_id (évite le message générique « Erreur »).
|
|
$sqlInsert = "
|
|
INSERT INTO inscriptions_epreuves_bib
|
|
(epr_id, epr_bib_start, epr_bib_finish, update_date, update_qui, eve_id)
|
|
VALUES
|
|
($epr_id, $intStart, $intEnd, NOW(), 'admin', $int_eve_id)
|
|
";
|
|
$qryInsert = $objDatabase->fxQuery($sqlInsert);
|
|
if ($qryInsert === false) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_insert_failed'),
|
|
];
|
|
}
|
|
|
|
$intBibId = 0;
|
|
if (method_exists($objDatabase, 'fxGetLastId')) {
|
|
$intBibId = (int)$objDatabase->fxGetLastId();
|
|
} elseif (isset($objDatabase->last_id)) {
|
|
$intBibId = (int)$objDatabase->last_id;
|
|
}
|
|
|
|
// Repli : si insert_id absent, retrouver la ligne fraîchement créée.
|
|
if ($intBibId <= 0) {
|
|
$intBibId = (int)$objDatabase->fxGetVar("
|
|
SELECT epr_bib_id
|
|
FROM inscriptions_epreuves_bib
|
|
WHERE epr_id = $epr_id
|
|
AND epr_bib_start = $intStart
|
|
AND epr_bib_finish = $intEnd
|
|
AND eve_id = $int_eve_id
|
|
ORDER BY epr_bib_id DESC
|
|
LIMIT 1
|
|
");
|
|
}
|
|
|
|
if ($intBibId <= 0) {
|
|
return [
|
|
'success' => false,
|
|
'message' => fxBibMsg('bib_v4_global_batch_gen_insert_failed'),
|
|
];
|
|
}
|
|
|
|
$tabCreated[] = [
|
|
'epr_id' => $epr_id,
|
|
'ranges' => [$intBibId],
|
|
'start' => $intStart,
|
|
'end' => $intEnd,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'plans' => $tabCreated,
|
|
];
|
|
}
|
|
|
|
/** Statistiques agrégées pour l'analyse du bloc généré. */
|
|
function fxBibBuildGlobalBatchGeneratedAnalysisStats($tabPlan) {
|
|
$intEpreuves = 0;
|
|
$intPending = 0;
|
|
$intBibs = 0;
|
|
|
|
foreach ($tabPlan as $item) {
|
|
if (!empty($item['skip'])) {
|
|
continue;
|
|
}
|
|
|
|
$intEpreuves++;
|
|
$intPending += (int)($item['nb_pending'] ?? 0);
|
|
$intStart = (int)($item['start'] ?? 0);
|
|
$intEnd = (int)($item['end'] ?? 0);
|
|
if ($intEnd >= $intStart && $intStart > 0) {
|
|
$intBibs += ($intEnd - $intStart + 1);
|
|
}
|
|
}
|
|
|
|
return [
|
|
'nb_epreuves' => $intEpreuves,
|
|
'nb_participants' => $intPending,
|
|
'nb_bibs' => $intBibs,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Simulation globale bloc généré (plages virtuelles, aucune écriture BD).
|
|
*
|
|
* @return array{success:bool, html?:string, info?:string, message?:string}
|
|
*/
|
|
function fxBibSimulateGlobalBatchGenerated($int_eve_id, $tabPlan, $strSort1, $strSort2, $strLangue) {
|
|
$int_eve_id = (int)$int_eve_id;
|
|
$check = fxBibValidateGeneratedRangePlan($int_eve_id, $tabPlan, $strLangue);
|
|
$tabSorts = is_array($strSort1)
|
|
? fxBibNormalizeSortKeysList($strSort1)
|
|
: fxBibNormalizeSortKeysList([$strSort1, $strSort2]);
|
|
|
|
if (!$check['success']) {
|
|
return $check;
|
|
}
|
|
|
|
$htmlParts = [];
|
|
$intParticipants = 0;
|
|
$intBibs = 0;
|
|
|
|
foreach ($tabPlan as $item) {
|
|
if (!empty($item['skip'])) {
|
|
continue;
|
|
}
|
|
|
|
$epr_id = (int)$item['epr_id'];
|
|
$intStart = (int)$item['start'];
|
|
$intEnd = (int)$item['end'];
|
|
$participants = fxGetParticipantsForBatchAssign($epr_id, $tabSorts);
|
|
$tabRanges = fxBibBuildVirtualRangesForPlan($intStart, $intEnd);
|
|
$simu = fxProcessBatchAssignments($epr_id, $participants, $tabRanges, 'simulation');
|
|
|
|
$intNbPending = count($participants);
|
|
$intParticipants += $intNbPending;
|
|
$intBibs += max(0, $intEnd - $intStart + 1);
|
|
|
|
$tabEpreuve = fxGetEpreuve($epr_id);
|
|
$strEprLabel = $tabEpreuve ? fxBibEpreuveDisplayName($tabEpreuve, $strLangue) : ('#' . $epr_id);
|
|
|
|
$strRangeLabel = fxBibMsg(
|
|
'bib_v4_global_batch_gen_range_preview',
|
|
$intStart,
|
|
$intEnd,
|
|
$intNbPending
|
|
);
|
|
|
|
$htmlParts[] = '<div class="bib-global-sim-section">'
|
|
. '<h4 class="bib-global-sim-section__title">' . fxBibEsc($strEprLabel) . '</h4>'
|
|
. '<p class="bib-global-sim-section__range text-muted small">' . fxBibEsc($strRangeLabel) . '</p>'
|
|
. renderBibView(
|
|
$epr_id,
|
|
0,
|
|
$strLangue,
|
|
'simulation',
|
|
$simu,
|
|
fxBibTexte('bib_v4_ajax_title_simulation'),
|
|
fxBibMsg(
|
|
'bib_v4_ajax_sim_summary',
|
|
max(0, $intEnd - $intStart + 1),
|
|
$intNbPending,
|
|
max(0, $intNbPending - count($simu))
|
|
)
|
|
)
|
|
. '</div>';
|
|
}
|
|
|
|
$info = fxBibMsg(
|
|
'bib_v4_ajax_global_gen_sim_summary',
|
|
fxBibBuildGlobalBatchGeneratedAnalysisStats($tabPlan)['nb_epreuves'],
|
|
$intBibs,
|
|
$intParticipants
|
|
);
|
|
|
|
$html = fxBibWrapGlobalSimView($info, implode('', $htmlParts), 'bib-global-sim-view--generated');
|
|
|
|
return [
|
|
'success' => true,
|
|
'html' => $html,
|
|
'info' => $info,
|
|
];
|
|
}
|