Compare commits
109 Commits
master
...
feature/ap
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ee8ee21d2 | |||
| 162052a2d1 | |||
| dabb797060 | |||
| 54d5363f09 | |||
| 85e030b93a | |||
| 1af97e7bb6 | |||
| 49d8bd23f4 | |||
| 2f699ed10d | |||
| a30f887489 | |||
| bdf5df0923 | |||
| 79bea0f9c7 | |||
| 088cfefee2 | |||
| 1baefb5f9c | |||
| 504f245eb5 | |||
| 088fd91617 | |||
| 238c09357e | |||
| c2b5b68568 | |||
| 789ce4947d | |||
| ef8304c617 | |||
| 3ed9f8e1fc | |||
| d9775ab315 | |||
| 8717130865 | |||
| 044aca6026 | |||
| 97e554fc20 | |||
| b5ca510f1f | |||
| 4d7ebeba85 | |||
| 382b83e690 | |||
| d016eacb57 | |||
| 8001389e39 | |||
| 0a944bd549 | |||
| 804a8bba18 | |||
| f6398c5035 | |||
| 025e145f6f | |||
| d006d75e53 | |||
| f83bc634a3 | |||
| b6f0b85140 | |||
| 517ff7dff6 | |||
| 9690f1884c | |||
| 35b5a2a605 | |||
| 27e1ce326c | |||
| ed1b5b5bd2 | |||
| f97ee2485a | |||
| 8cfd6f2e35 | |||
| 4cdd814945 | |||
| dab41e4857 | |||
| a762f5e599 | |||
| 9d0e14b74b | |||
| bd0da2651b | |||
| 889ceddf79 | |||
| bba116e7b6 | |||
| 525ddba26f | |||
| 5d35f38985 | |||
| b4864a2278 | |||
| a0d879502a | |||
| b2ed26a0aa | |||
| 7a1685e7fa | |||
| f7b1a18365 | |||
| 181b3f7d1c | |||
| 13d6f0752a | |||
| 98109fa0ab | |||
| 0293ce9099 | |||
| 36dc2f6ab0 | |||
| 2efb46fc59 | |||
| ac21e4aa81 | |||
| 509619520d | |||
| de7e5ebe7f | |||
| 891fed7c66 | |||
| f7f38fa752 | |||
| 7b87f18d1a | |||
| 4bd33db912 | |||
| 41ecfd0756 | |||
| afc71f0d58 | |||
| a5d85d28fb | |||
| f55852a14f | |||
| 3eff5b3c3f | |||
| 5c35dd3c1b | |||
| 1f5cbcc8ba | |||
| 175d7e11db | |||
| 95204ed0f5 | |||
| bb62c4c8b6 | |||
| 30bdcd1423 | |||
| 734f9a899d | |||
| 688f864c95 | |||
| 57ffc59524 | |||
| 714b0e11ed | |||
| b3ebb337c4 | |||
| cc897bcaaa | |||
| 722488006d | |||
| 182083b6ce | |||
| 0dae4463ca | |||
| 0cf57c81fd | |||
| 95e4e7bb1a | |||
| b9f1b7d550 | |||
| 3b5a82b01c | |||
| 623895be87 | |||
| 911fbc788c | |||
| 62a6f4b7f6 | |||
| 6d5dc43a5a | |||
| 93e198372d | |||
| 4d5836b0ad | |||
| fb2525dfa4 | |||
| db13175202 | |||
| 1d850d035b | |||
| 96f78ebcb0 | |||
| 5957c72884 | |||
| 16cda56e02 | |||
| 5fa2bc3db5 | |||
| f90347c5ba | |||
| 9b36733035 |
45
.gitignore
vendored
45
.gitignore
vendored
@ -51,22 +51,31 @@ Thumbs.db
|
||||
/data/
|
||||
/pdf/dons/
|
||||
/images/evenements/
|
||||
v3_ci4/writable/
|
||||
/v3_ci4/writable/
|
||||
*.log
|
||||
error_log
|
||||
webhooks/paypaldevclient/paypal_incoming.json
|
||||
webhooks/paypaldevtest/paypal_incoming.json
|
||||
preprod/dons
|
||||
preprod/images/evenements
|
||||
preprod/pdf/dons/
|
||||
preprod/pdf/questions/
|
||||
preprod/images/backgrounds/
|
||||
preprod/pdf/cartes/
|
||||
preprod/pdf/template_carte/
|
||||
preprod/pdf/template_dons/
|
||||
upload/
|
||||
test/
|
||||
tpp/
|
||||
qr/
|
||||
bp/
|
||||
fnq/
|
||||
/error_log
|
||||
/webhooks/paypaldevclient/paypal_incoming.json
|
||||
/webhooks/paypaldevtest/paypal_incoming.json
|
||||
/preprod/dons
|
||||
/preprod/images/evenements
|
||||
/preprod/pdf/dons/
|
||||
/preprod/pdf/questions/
|
||||
/preprod/images/backgrounds/
|
||||
/preprod/pdf/cartes/
|
||||
/preprod/pdf/template_carte/
|
||||
/preprod/pdf/template_dons/
|
||||
/upload/
|
||||
/test/
|
||||
/tpp/
|
||||
/qr/
|
||||
/bp/
|
||||
/fnq/
|
||||
/images/backgrounds/
|
||||
/pdf/questions/
|
||||
/preprod/images/backgrounds/
|
||||
/preprod/images/evenements/
|
||||
/v3_ci4/writable/debugbar/
|
||||
/webhooks/paypaldevclient/
|
||||
/webhooks/paypaldevtest/
|
||||
webhooks/paypal/
|
||||
paypal_advanced/error_log
|
||||
25
.vscode/settings.json
vendored
Normal file
25
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"sqltools.connections": [
|
||||
{
|
||||
"mysqlOptions": {
|
||||
"authProtocol": "default",
|
||||
"enableSsl": "Disabled"
|
||||
},
|
||||
"ssh": "Enabled",
|
||||
"previewLimit": 50,
|
||||
"server": "localhost",
|
||||
"port": 3306,
|
||||
"sshOptions": {
|
||||
"port": 7822,
|
||||
"host": "104.254.182.111",
|
||||
"username": "devinscription",
|
||||
"password": "M-G7+[NdA34H"
|
||||
},
|
||||
"driver": "MariaDB",
|
||||
"name": "astral(dev) ms1inscription",
|
||||
"username": "devinscription_bd",
|
||||
"password": "x$@_v0-l_I((",
|
||||
"database": "devinscription_preprod"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -394,7 +394,7 @@ if ($action == 'batch_go') {
|
||||
|
||||
$nextBib = fxGetNextAvailableBib($epr_id, $tabRanges);
|
||||
$simu = fxProcessBatchAssignments($epr_id, $participants, $tabRanges, 'simulation');
|
||||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants);
|
||||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id);
|
||||
|
||||
$info = "{$summary['nb_dispo']} disponibles / {$summary['nb_participants']} à assigner → manque {$summary['nb_manque']}";
|
||||
// =====================
|
||||
@ -451,7 +451,7 @@ if ($action == 'batch_apply') {
|
||||
return in_array((int)$r['epr_bib_id'], $ids);
|
||||
});
|
||||
|
||||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants);
|
||||
$summary = fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id);
|
||||
|
||||
$assigned = count($exec);
|
||||
$total = count($participants);
|
||||
@ -605,6 +605,45 @@ if ($action == 'save_team_mode') {
|
||||
|
||||
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).
|
||||
// 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' => 'epr_id invalide'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$result = fxSaveBibAutoConfig($epr_id, is_array($ranges) ? $ranges : [], $active);
|
||||
|
||||
if (!$result['success']) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $result['message'] ?? 'Erreur'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$tabBibStats = fxInfosBibRange($epr_id);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'auto_active' => !empty($result['auto_active']),
|
||||
'html' => renderBibRanges($tabBibStats, $epr_id, 'assign')
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// ACTION INVALIDE
|
||||
// =====================
|
||||
|
||||
@ -713,8 +713,8 @@ require_once("inc_header.php");
|
||||
break;
|
||||
case 'compte_inc_tableau_dossards':
|
||||
$blnBoutonRetour = false;
|
||||
|
||||
include("inc_tableau_dossards.php");
|
||||
include("inc_tableau_dossards_v2.php");
|
||||
break;
|
||||
case 'compte_inc_tableau_epreuves':
|
||||
$blnBoutonRetour = false;
|
||||
|
||||
@ -1038,9 +1038,8 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active {
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
}
|
||||
.bib-view.team-mode .bib-view-header {
|
||||
grid-template-columns: 1.6fr 1fr 1fr 0.7fr;
|
||||
}
|
||||
|
||||
|
||||
.bib-view-header > div {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
@ -1050,8 +1049,9 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active {
|
||||
grid-template-columns: 1.6fr 1fr 0.7fr;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
}
|
||||
.bib-view.team-mode .bib-view-row {
|
||||
grid-template-columns: 1.6fr 1fr 1fr 0.7fr;
|
||||
.bib-view.team-mode .bib-view-header,
|
||||
.bib-view.team-mode .bib-view-row{
|
||||
grid-template-columns: 1.5fr 1fr 0.7fr 1fr 0.8fr;
|
||||
}
|
||||
.bib-view-row:nth-of-type(odd) {
|
||||
background: #f3f3f3;
|
||||
@ -1101,6 +1101,30 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active {
|
||||
display:none;
|
||||
}
|
||||
|
||||
/* MSIN-4379 — Étape 2 : styles du mode « auto » (masque batch, verrouille édition des plages).
|
||||
Prochain tour : étape 6–7 (logique PHP à l'achat, pas de CSS supplémentaire prévu). */
|
||||
.epr-row.auto-mode .btn-assign-batch,
|
||||
.epr-row.auto-mode .btn-reset,
|
||||
.epr-row.auto-mode .batch-config-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.epr-row.auto-mode .btn-auto {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.epr-row.auto-mode .btn-save-range,
|
||||
.epr-row.auto-mode .btn-delete-range,
|
||||
.epr-row.auto-mode .btn-add-range {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.epr-row.auto-mode .bib-start,
|
||||
.epr-row.auto-mode .bib-end {
|
||||
pointer-events: none;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.epr-row.batch-mode .btn-go-batch {
|
||||
display: none;
|
||||
}
|
||||
@ -1144,10 +1168,7 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active {
|
||||
.bib-view-header > div{
|
||||
white-space:nowrap;
|
||||
}
|
||||
.bib-view.team-mode .bib-view-header,
|
||||
.bib-view.team-mode .bib-view-row{
|
||||
grid-template-columns: 1.5fr 1fr 1fr 0.8fr;
|
||||
}
|
||||
|
||||
.team-mode-title{
|
||||
font-size:11px;
|
||||
color:#666;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* Date: 2020-05-26
|
||||
* Time: 16:51
|
||||
*/
|
||||
require_once("PHPColors/Color.php"); // inclure la class
|
||||
require_once(__DIR__ . '/../PHPColors/Color.php'); // inclure la class
|
||||
use Mexitek\PHPColors\Color; // utiliser le namepace de la class
|
||||
global $vDomaine, $vRepertoireFichiers;
|
||||
|
||||
|
||||
3
deploy_dev.php
Normal file
3
deploy_dev.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo shell_exec('/home/devinscription/deploy/deploy_dev.sh 2>&1');
|
||||
@ -259,11 +259,11 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
|
||||
|
||||
//MSIN-3860
|
||||
|
||||
if (!getCookie('cookiesAccepted') && !getCookie('cookiesRejected')) {
|
||||
// if (!getCookie('cookiesAccepted') && !getCookie('cookiesRejected')) {
|
||||
|
||||
|
||||
$('#cookieConsent').fadeIn();
|
||||
}
|
||||
// $('#cookieConsent').fadeIn();
|
||||
// }
|
||||
|
||||
// Handle the acceptance of cookies
|
||||
$('#acceptCookies').click(function() {
|
||||
|
||||
@ -1948,6 +1948,189 @@ if ($strLangue == 'fr') {
|
||||
|
||||
if (moduleBib) {
|
||||
|
||||
// ============================================================
|
||||
// MSIN-4379 — Étape 2 : assignation automatique (interface JS)
|
||||
// Prochain tour : étape 6 (fxAssignAutoBibForParticipant), étape 7 (fxMajCommande).
|
||||
// ============================================================
|
||||
|
||||
/** MSIN-4379 — Compte les séquences cochées et met à jour le texte d'aide. */
|
||||
function updateAutoSelectionInfo(row) {
|
||||
|
||||
if (!row) return;
|
||||
|
||||
let count = row.querySelectorAll('.batch-select-range:checked').length;
|
||||
let info = row.querySelector('.auto-info');
|
||||
|
||||
if (!info) return;
|
||||
|
||||
if (count === 0) {
|
||||
info.textContent = 'Sélectionnez au moins une séquence.';
|
||||
} else {
|
||||
info.textContent = count + ' séquence(s) sélectionnée(s).';
|
||||
}
|
||||
}
|
||||
|
||||
/** MSIN-4379 — Après sauvegarde : badge, libellé du bouton, bouton Désactiver. */
|
||||
function syncAutoUiState(row, isActive) {
|
||||
|
||||
if (!row) return;
|
||||
|
||||
let btnAuto = row.querySelector('.btn-auto');
|
||||
let badge = row.querySelector('.bib-auto-badge');
|
||||
let btnDesactiver = row.querySelector('.btn-desactiver-auto');
|
||||
|
||||
row.dataset.autoActive = isActive ? '1' : '0';
|
||||
|
||||
if (isActive) {
|
||||
row.classList.add('auto-enabled');
|
||||
} else {
|
||||
row.classList.remove('auto-enabled');
|
||||
}
|
||||
|
||||
if (btnAuto) {
|
||||
btnAuto.textContent = isActive ? 'Configurer automatique' : 'Activer automatique';
|
||||
btnAuto.classList.toggle('btn-success', isActive);
|
||||
btnAuto.classList.toggle('btn-secondary', !isActive);
|
||||
}
|
||||
|
||||
if (badge) {
|
||||
badge.style.display = isActive ? '' : 'none';
|
||||
}
|
||||
|
||||
if (btnDesactiver) {
|
||||
btnDesactiver.style.display = isActive ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/** MSIN-4379 — Quitte le mode édition auto sans sauver ; recharge les plages (mode assign). */
|
||||
function exitAutoMode(row) {
|
||||
|
||||
if (!row) return;
|
||||
|
||||
row.classList.remove('auto-mode');
|
||||
|
||||
let container = row.querySelector('.bib-container');
|
||||
if (container) {
|
||||
container.classList.remove('batch-mode');
|
||||
}
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
input.removeAttribute('readonly');
|
||||
});
|
||||
|
||||
let autoConfig = row.querySelector('.auto-config-container');
|
||||
if (autoConfig) {
|
||||
autoConfig.style.display = 'none';
|
||||
}
|
||||
|
||||
let btnAuto = row.querySelector('.btn-auto');
|
||||
if (btnAuto) {
|
||||
btnAuto.style.display = '';
|
||||
}
|
||||
|
||||
let btnBatch = row.querySelector('.btn-assign-batch');
|
||||
if (btnBatch) {
|
||||
btnBatch.style.display = '';
|
||||
}
|
||||
|
||||
let btnReset = row.querySelector('.btn-reset');
|
||||
if (btnReset) {
|
||||
btnReset.style.display = '';
|
||||
}
|
||||
|
||||
fetch('/ajax_bib_range.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body:
|
||||
'action=refresh_ranges'
|
||||
+ '&epr_id=' + encodeURIComponent(row.dataset.eprId)
|
||||
+ '&mode=assign'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
if (!data.success) return;
|
||||
|
||||
let bibContainer = row.querySelector('.epr-block:nth-child(2) .bib-container');
|
||||
if (bibContainer) {
|
||||
bibContainer.innerHTML = data.html;
|
||||
}
|
||||
|
||||
syncBibUiState(row);
|
||||
});
|
||||
}
|
||||
|
||||
/** MSIN-4379 — Ouvre le mode édition : checkboxes, bloc Accepter/Annuler, refresh mode=auto. */
|
||||
function enterAutoMode(row) {
|
||||
|
||||
if (!row) return;
|
||||
|
||||
if (row.classList.contains('batch-mode') || row.classList.contains('reset-mode')) {
|
||||
return;
|
||||
}
|
||||
|
||||
row.classList.add('auto-mode');
|
||||
|
||||
let container = row.querySelector('.bib-container');
|
||||
if (container) {
|
||||
container.classList.add('batch-mode');
|
||||
}
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
let autoConfig = row.querySelector('.auto-config-container');
|
||||
if (autoConfig) {
|
||||
autoConfig.style.display = 'block';
|
||||
}
|
||||
|
||||
let btnAuto = row.querySelector('.btn-auto');
|
||||
if (btnAuto) {
|
||||
btnAuto.style.display = 'none';
|
||||
}
|
||||
|
||||
let btnBatch = row.querySelector('.btn-assign-batch');
|
||||
if (btnBatch) {
|
||||
btnBatch.style.display = 'none';
|
||||
}
|
||||
|
||||
let btnReset = row.querySelector('.btn-reset');
|
||||
if (btnReset) {
|
||||
btnReset.style.display = 'none';
|
||||
}
|
||||
|
||||
fetch('/ajax_bib_range.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body:
|
||||
'action=refresh_ranges'
|
||||
+ '&epr_id=' + encodeURIComponent(row.dataset.eprId)
|
||||
+ '&mode=auto'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
if (!data.success) return;
|
||||
|
||||
let bibContainer = row.querySelector('.epr-block:nth-child(2) .bib-container');
|
||||
if (!bibContainer) return;
|
||||
|
||||
bibContainer.innerHTML = data.html;
|
||||
bibContainer.classList.add('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
updateAutoSelectionInfo(row);
|
||||
});
|
||||
}
|
||||
|
||||
function syncBibUiState(row) {
|
||||
|
||||
let avecEl = row.querySelector('.bib-avec');
|
||||
@ -2039,7 +2222,12 @@ if ($strLangue == 'fr') {
|
||||
if (totalEl) totalEl.textContent = data.info.total;
|
||||
if (avecEl) avecEl.textContent = data.info.avec_bib;
|
||||
syncBibUiState(row);
|
||||
let sansBib = parseInt(data.info.sans_bib || 0, 10);
|
||||
let sansBib = parseInt(
|
||||
(data.info.a_assigner !== undefined && data.info.a_assigner !== null)
|
||||
? data.info.a_assigner
|
||||
: (data.info.sans_bib || 0),
|
||||
10
|
||||
);
|
||||
if (isNaN(sansBib)) sansBib = 0;
|
||||
let isResetMode = row.dataset.mode === 'reset';
|
||||
let message = '';
|
||||
@ -2108,6 +2296,12 @@ if ($strLangue == 'fr') {
|
||||
let row = cb.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
// MSIN-4379 — En mode auto, pas de logique batch (refresh_ranges / GO).
|
||||
if (row.classList.contains('auto-mode')) {
|
||||
updateAutoSelectionInfo(row);
|
||||
return;
|
||||
}
|
||||
|
||||
if (row.dataset.loading === '1') return;
|
||||
let existing = document.querySelector('.epr-row-view');
|
||||
if (existing) existing.remove();
|
||||
@ -2332,6 +2526,23 @@ if ($strLangue == 'fr') {
|
||||
|
||||
let container = btnView.closest('.epr-block');
|
||||
|
||||
// Vérifier si une vue est déjà ouverte
|
||||
let existing = document.querySelector('.epr-row-view');
|
||||
|
||||
// Toggle : si c'est le même œil qui a ouvert la vue, on la ferme et on s'arrête
|
||||
if (existing
|
||||
&& existing.dataset.eprId === epr_id
|
||||
&& existing.dataset.rangeId === range_id
|
||||
) {
|
||||
existing.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// Un autre œil a été cliqué : fermer la vue précédente avant d'ouvrir la nouvelle
|
||||
if (existing) {
|
||||
existing.remove();
|
||||
}
|
||||
|
||||
fetch('/ajax_bib_range.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -2360,14 +2571,17 @@ if ($strLangue == 'fr') {
|
||||
|
||||
let row = btnView.closest('.epr-row');
|
||||
|
||||
// 1. Supprimer toute vue existante
|
||||
let existing = document.querySelector('.epr-row-view');
|
||||
if (existing) {
|
||||
existing.remove();
|
||||
}
|
||||
|
||||
// 2. Injecter sous la bonne ligne
|
||||
// Injecter la nouvelle vue sous la ligne du bouton cliqué,
|
||||
// en mémorisant epr_id et range_id pour le toggle suivant
|
||||
row.insertAdjacentHTML('afterend', data.html);
|
||||
|
||||
// Stocker les identifiants sur la vue injectée pour pouvoir détecter
|
||||
// le 2e clic sur le même œil
|
||||
let newView = row.nextElementSibling;
|
||||
if (newView && newView.classList.contains('epr-row-view')) {
|
||||
newView.dataset.eprId = epr_id;
|
||||
newView.dataset.rangeId = range_id;
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
@ -2405,6 +2619,11 @@ if ($strLangue == 'fr') {
|
||||
let row = btnBatch.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
// MSIN-4379 — Batch et auto sont mutuellement exclusifs.
|
||||
if (row.classList.contains('auto-mode')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let container = row.querySelector('.bib-container');
|
||||
if (!container) return;
|
||||
|
||||
@ -2529,6 +2748,11 @@ if ($strLangue == 'fr') {
|
||||
let row = btnReset.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
// MSIN-4379 — Reset et auto sont mutuellement exclusifs.
|
||||
if (row.classList.contains('auto-mode')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let container = row.querySelector('.bib-container');
|
||||
if (!container) return;
|
||||
|
||||
@ -2830,6 +3054,125 @@ if ($strLangue == 'fr') {
|
||||
return;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// MSIN-4379 — Étape 2 : AUTO DOSSARD (clics Accepter / Annuler / Désactiver / Activer)
|
||||
// Prochain tour : étape 6–7 (assignation PHP à l'inscription).
|
||||
// =====================
|
||||
let btnAccepterAuto = e.target.closest('.btn-accepter-auto');
|
||||
if (btnAccepterAuto) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
let row = btnAccepterAuto.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
let selected = [];
|
||||
|
||||
row.querySelectorAll('.batch-select-range:checked').forEach(cb => {
|
||||
selected.push(cb.dataset.rangeId);
|
||||
});
|
||||
|
||||
if (selected.length === 0) {
|
||||
alert('Sélectionnez au moins une séquence');
|
||||
return;
|
||||
}
|
||||
|
||||
// MSIN-4379 — Persiste epr_bib_auto=1 sur les séquences choisies (save_auto_config).
|
||||
fetch('/ajax_bib_range.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body:
|
||||
'action=save_auto_config'
|
||||
+ '&epr_id=' + encodeURIComponent(row.dataset.eprId)
|
||||
+ '&active=1'
|
||||
+ '&ranges=' + encodeURIComponent(JSON.stringify(selected))
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
if (!data.success) {
|
||||
alert(data.message || 'Erreur');
|
||||
return;
|
||||
}
|
||||
|
||||
syncAutoUiState(row, true);
|
||||
exitAutoMode(row);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// MSIN-4379 — Annule l'édition sans appeler save_auto_config.
|
||||
let btnAnnulerAuto = e.target.closest('.btn-annuler-auto');
|
||||
if (btnAnnulerAuto) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
let row = btnAnnulerAuto.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
exitAutoMode(row);
|
||||
return;
|
||||
}
|
||||
|
||||
// MSIN-4379 — Désactive l'auto en base (active=0, toutes les séquences à 0).
|
||||
let btnDesactiverAuto = e.target.closest('.btn-desactiver-auto');
|
||||
if (btnDesactiverAuto) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
let row = btnDesactiverAuto.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
if (!confirm('Désactiver l\'assignation automatique pour cette épreuve ?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/ajax_bib_range.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body:
|
||||
'action=save_auto_config'
|
||||
+ '&epr_id=' + encodeURIComponent(row.dataset.eprId)
|
||||
+ '&active=0'
|
||||
+ '&ranges=' + encodeURIComponent('[]')
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
if (!data.success) {
|
||||
alert(data.message || 'Erreur');
|
||||
return;
|
||||
}
|
||||
|
||||
syncAutoUiState(row, false);
|
||||
exitAutoMode(row);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// MSIN-4379 — Entrée dans le mode configuration auto.
|
||||
let btnAuto = e.target.closest('.btn-auto');
|
||||
if (btnAuto) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
let row = btnAuto.closest('.epr-row');
|
||||
if (!row) return;
|
||||
|
||||
if (row.classList.contains('batch-mode') || row.classList.contains('reset-mode')) {
|
||||
return;
|
||||
}
|
||||
|
||||
enterAutoMode(row);
|
||||
return;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// CREATE
|
||||
// =====================
|
||||
|
||||
@ -65,9 +65,14 @@ if ($intEveId != 0) {
|
||||
<a class="nav-list" href="<?php echo $vDomaine . "/" . $strCode; ?>bib_assignment?a=show_bib_dupes&promoteur_eve_id=<?php echo urlencode(base64_encode($intEveId)); ?>"> <i class="fa fa-clone" aria-hidden="true"></i> <?php echo afficheTexte('tableau_dossards_doublons', 0) ;?>
|
||||
</a>
|
||||
</li> </ul>
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
if (isset($_SESSION['usa_id'])) {
|
||||
fxShowBibTool4($strBibCode, $intEveId, $strLangue);
|
||||
}
|
||||
fxShowBibTool3($strBibCode, $intEveId, $strLangue);
|
||||
|
||||
?>
|
||||
|
||||
<a class="btn btn-primary rounded-pill" id="link_back" href="<?php echo $vDomaine . $strPage . "/inc_tableau_promoteur?promoteur_eve_id=" . urlencode(base64_encode($intEveId)); ?>">
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
require_once('php/inc_start_time.php');
|
||||
require_once('php/inc_fonctions.php');
|
||||
require_once('php/inc_fx_messages.php');
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
global $vPage, $vDomaine;
|
||||
$strLangue = 'fr';
|
||||
$strCode = "accueil";
|
||||
|
||||
13
min/.htaccess
Normal file
13
min/.htaccess
Normal file
@ -0,0 +1,13 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
|
||||
# You may need RewriteBase on some servers
|
||||
#RewriteBase /min
|
||||
|
||||
# rewrite URLs like "/min/f=..." to "/min/?f=..."
|
||||
RewriteRule ^([bfg]=.*) index.php?$1 [L,NE]
|
||||
</IfModule>
|
||||
<IfModule mod_env.c>
|
||||
# In case AddOutputFilterByType has been added
|
||||
SetEnv no-gzip
|
||||
</IfModule>
|
||||
682
ms1_kc_set.php
Normal file
682
ms1_kc_set.php
Normal file
@ -0,0 +1,682 @@
|
||||
<?php
|
||||
/**
|
||||
* Outil temporaire : modifier key_chain_http pour un pk_key_chain.
|
||||
* Accès 1 : /ms1_kc_set.php?k=<KEYCHAIN_HTTP_EDIT_SECRET>
|
||||
* Accès 2 : compte connecté dont com_id est dans KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS
|
||||
*/
|
||||
$blnNoMaintenance = true;
|
||||
session_start();
|
||||
|
||||
require_once __DIR__ . '/php/inc_fonctions.php';
|
||||
|
||||
header('X-Robots-Tag: noindex, nofollow');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
|
||||
global $objDatabase, $vDomaine;
|
||||
|
||||
function kc_set_allowed_com_ids()
|
||||
{
|
||||
if (!defined('KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS') || KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS === '') {
|
||||
return [];
|
||||
}
|
||||
$arr = array_map('intval', explode(',', KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS));
|
||||
return array_values(array_filter($arr, function ($id) {
|
||||
return $id > 0;
|
||||
}));
|
||||
}
|
||||
|
||||
function kc_set_com_id_authorized()
|
||||
{
|
||||
if (!isset($_SESSION['com_id']) || (int) $_SESSION['com_id'] <= 0) {
|
||||
return false;
|
||||
}
|
||||
return in_array((int) $_SESSION['com_id'], kc_set_allowed_com_ids(), true);
|
||||
}
|
||||
|
||||
$strSecret = isset($_GET['k']) ? (string) $_GET['k'] : '';
|
||||
$blnAuthSecret = ($strSecret !== '' && hash_equals(KEYCHAIN_HTTP_EDIT_SECRET, $strSecret));
|
||||
if ($blnAuthSecret) {
|
||||
$_SESSION['kc_edit_auth_key'] = 1;
|
||||
}
|
||||
$blnAuthUser = kc_set_com_id_authorized();
|
||||
$blnAuth = $blnAuthSecret || $blnAuthUser || !empty($_SESSION['kc_edit_auth_key']);
|
||||
|
||||
if (!$blnAuth) {
|
||||
if (!isset($_SESSION['com_id']) && kc_set_allowed_com_ids() !== []) {
|
||||
$_SESSION['redirect_after_login'] = $_SERVER['REQUEST_URI'];
|
||||
header('Location: ' . $vDomaine . '/compte');
|
||||
exit;
|
||||
}
|
||||
http_response_code(403);
|
||||
echo '<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>Accès refusé</title></head><body>';
|
||||
echo '<p>Accès refusé.</p>';
|
||||
if (kc_set_allowed_com_ids() !== []) {
|
||||
echo '<p><a href="' . htmlspecialchars($vDomaine . '/compte', ENT_QUOTES, 'UTF-8') . '">Se connecter</a></p>';
|
||||
}
|
||||
echo '</body></html>';
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($_SESSION['kc_edit_csrf'])) {
|
||||
$_SESSION['kc_edit_csrf'] = bin2hex(random_bytes(16));
|
||||
}
|
||||
$strCsrf = $_SESSION['kc_edit_csrf'];
|
||||
$strBasePath = $_SERVER['PHP_SELF'];
|
||||
|
||||
function kc_set_page_url(array $params = [])
|
||||
{
|
||||
global $strBasePath;
|
||||
$query = $params;
|
||||
if (!empty($_SESSION['kc_edit_auth_key']) && !isset($query['k'])) {
|
||||
$query = array_merge(['k' => KEYCHAIN_HTTP_EDIT_SECRET], $query);
|
||||
}
|
||||
$qs = http_build_query($query);
|
||||
return $strBasePath . ($qs !== '' ? '?' . $qs : '');
|
||||
}
|
||||
|
||||
$strPageUrl = kc_set_page_url();
|
||||
$strBaseUrlHtml = htmlspecialchars($strPageUrl, ENT_QUOTES, 'UTF-8');
|
||||
$blnCanShareLink = !empty($_SESSION['kc_edit_auth_key']);
|
||||
$strShareUrl = '';
|
||||
if ($blnCanShareLink) {
|
||||
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||
$strShareUrl = $scheme . '://' . $_SERVER['HTTP_HOST'] . kc_set_page_url(['k' => KEYCHAIN_HTTP_EDIT_SECRET]);
|
||||
}
|
||||
|
||||
$strUserName = '';
|
||||
if ($blnAuthUser && !empty($_SESSION['com_prenom'])) {
|
||||
$strUserName = trim((string) $_SESSION['com_prenom']);
|
||||
} elseif ($blnAuthUser && !empty($_SESSION['com_info']['com_prenom'])) {
|
||||
$strUserName = trim((string) $_SESSION['com_info']['com_prenom']);
|
||||
}
|
||||
|
||||
$strMessage = '';
|
||||
$strMessageClass = '';
|
||||
$intPk = 0;
|
||||
$strCurrentHttp = '';
|
||||
$blnShowUrlForm = false;
|
||||
$strVehiculeSaisi = '';
|
||||
|
||||
if (!empty($_GET['ok'])) {
|
||||
$strMessage = 'Le lien de votre code QR a été enregistré. Vous pouvez modifier un autre véhicule ci-dessous.';
|
||||
$strMessageClass = 'ok';
|
||||
}
|
||||
|
||||
function kc_set_parse_vehicule_no($input)
|
||||
{
|
||||
$input = trim((string) $input);
|
||||
if ($input === '' || !ctype_digit($input)) {
|
||||
return 0;
|
||||
}
|
||||
$no = intval($input);
|
||||
if ($no <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return $no + KEYCHAIN_HTTP_EDIT_SHIFT;
|
||||
}
|
||||
|
||||
function kc_set_validate_url($url)
|
||||
{
|
||||
$url = trim($url);
|
||||
if ($url === '') {
|
||||
return false;
|
||||
}
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
return false;
|
||||
}
|
||||
$parts = parse_url($url);
|
||||
if (empty($parts['scheme']) || !in_array(strtolower($parts['scheme']), ['http', 'https'], true)) {
|
||||
return false;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
function kc_set_save_lien_for_pk($intPk, $strVehiculeSaisi, $strNewHttp)
|
||||
{
|
||||
global $objDatabase, $strMessage, $strMessageClass, $strCurrentHttp, $blnShowUrlForm;
|
||||
|
||||
if ($strVehiculeSaisi !== '' && kc_set_parse_vehicule_no($strVehiculeSaisi) !== $intPk) {
|
||||
$intPk = 0;
|
||||
}
|
||||
if ($intPk <= 0) {
|
||||
$strMessage = 'Veuillez recommencer avec votre numéro de véhicule.';
|
||||
$strMessageClass = 'err';
|
||||
return false;
|
||||
}
|
||||
$sqlCheck = 'SELECT pk_key_chain FROM key_chain WHERE pk_key_chain = ' . $intPk;
|
||||
if ($objDatabase->fxGetRow($sqlCheck) === null) {
|
||||
$strMessage = 'Code QR introuvable. Vérifiez votre numéro de véhicule.';
|
||||
$strMessageClass = 'err';
|
||||
return false;
|
||||
}
|
||||
$sqlUpdate = "UPDATE key_chain SET key_chain_http = '" . $objDatabase->fxEscape($strNewHttp) . "' WHERE pk_key_chain = " . $intPk;
|
||||
if ($objDatabase->fxQuery($sqlUpdate) === false) {
|
||||
$strMessage = 'Impossible d’enregistrer pour le moment. Réessayez plus tard.';
|
||||
$strMessageClass = 'err';
|
||||
$blnShowUrlForm = true;
|
||||
$strCurrentHttp = $strNewHttp;
|
||||
return false;
|
||||
}
|
||||
header('Location: ' . kc_set_page_url(['ok' => '1']));
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$strPostedCsrf = isset($_POST['csrf']) ? (string) $_POST['csrf'] : '';
|
||||
if (!hash_equals($strCsrf, $strPostedCsrf)) {
|
||||
$strMessage = 'Veuillez recharger la page et réessayer.';
|
||||
$strMessageClass = 'err';
|
||||
} else {
|
||||
$strAction = isset($_POST['action']) ? (string) $_POST['action'] : '';
|
||||
|
||||
if ($strAction === 'load') {
|
||||
$strVehiculeSaisi = isset($_POST['vehicule_no']) ? trim((string) $_POST['vehicule_no']) : '';
|
||||
$intPk = kc_set_parse_vehicule_no($strVehiculeSaisi);
|
||||
if ($intPk <= 0) {
|
||||
$strMessage = 'Veuillez entrer un numéro de véhicule valide.';
|
||||
$strMessageClass = 'err';
|
||||
} else {
|
||||
$sql = 'SELECT key_chain_http FROM key_chain WHERE pk_key_chain = ' . $intPk;
|
||||
$row = $objDatabase->fxGetRow($sql);
|
||||
if ($row === null || !isset($row['key_chain_http'])) {
|
||||
$strMessage = 'Aucun code QR trouvé pour ce numéro de véhicule.';
|
||||
$strMessageClass = 'err';
|
||||
} else {
|
||||
$strCurrentHttp = $row['key_chain_http'];
|
||||
$blnShowUrlForm = true;
|
||||
}
|
||||
}
|
||||
} elseif ($strAction === 'save') {
|
||||
$intPk = intval(isset($_POST['pk']) ? $_POST['pk'] : 0);
|
||||
$strVehiculeSaisi = isset($_POST['vehicule_no']) ? trim((string) $_POST['vehicule_no']) : '';
|
||||
$strLienPost = isset($_POST['lien_qr']) ? trim((string) $_POST['lien_qr']) : '';
|
||||
$strNewHttp = kc_set_validate_url($strLienPost);
|
||||
if ($strNewHttp === false) {
|
||||
$strMessage = 'Veuillez entrer une adresse Web valide (commençant par http:// ou https://).';
|
||||
$strMessageClass = 'err';
|
||||
$blnShowUrlForm = true;
|
||||
$strCurrentHttp = $strLienPost;
|
||||
} else {
|
||||
kc_set_save_lien_for_pk($intPk, $strVehiculeSaisi, $strNewHttp);
|
||||
}
|
||||
} elseif ($strAction === 'save_ms1') {
|
||||
$intPk = intval(isset($_POST['pk']) ? $_POST['pk'] : 0);
|
||||
$strVehiculeSaisi = isset($_POST['vehicule_no']) ? trim((string) $_POST['vehicule_no']) : '';
|
||||
kc_set_save_lien_for_pk($intPk, $strVehiculeSaisi, 'https://ms1.ca');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Code QR — lien de redirection</title>
|
||||
<style>
|
||||
:root {
|
||||
--ms1-orange: #ff8c00;
|
||||
--ms1-orange-dark: #e67a00;
|
||||
--ms1-ink: #1a1a2e;
|
||||
--ms1-card: #ffffff;
|
||||
--ms1-muted: #5c6370;
|
||||
--ms1-ok: #0d7a4a;
|
||||
--ms1-err: #b42318;
|
||||
--radius: 16px;
|
||||
--shadow: 0 12px 40px rgba(26, 26, 46, 0.12);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
|
||||
color: var(--ms1-ink);
|
||||
background:
|
||||
radial-gradient(ellipse 80% 50% at 50% -10%, rgba(255, 140, 0, 0.25), transparent),
|
||||
linear-gradient(160deg, #f8f4ef 0%, #eef2f7 45%, #e8edf5 100%);
|
||||
padding: 1.5rem 1rem 3rem;
|
||||
}
|
||||
|
||||
.page {
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
animation: fadeUp 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeUp {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.hero {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.qr-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
margin: 0 auto 0.75rem;
|
||||
background: var(--ms1-ink);
|
||||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 4px;
|
||||
box-shadow: 0 6px 20px rgba(26, 26, 46, 0.2);
|
||||
}
|
||||
|
||||
.qr-icon span {
|
||||
background: var(--ms1-orange);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.qr-icon span:nth-child(5) { background: #fff; }
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.user-bar {
|
||||
margin-top: 0.5rem;
|
||||
color: var(--ms1-muted);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.intro {
|
||||
text-align: center;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.6;
|
||||
color: var(--ms1-muted);
|
||||
margin: 0 0 1.5rem;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.steps {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.step {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
background: #dde3eb;
|
||||
color: var(--ms1-muted);
|
||||
transition: transform 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.step.active {
|
||||
background: var(--ms1-orange);
|
||||
color: #fff;
|
||||
transform: scale(1.08);
|
||||
box-shadow: 0 4px 14px rgba(255, 140, 0, 0.45);
|
||||
}
|
||||
|
||||
.step.done {
|
||||
background: var(--ms1-ok);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.step-line {
|
||||
width: 2rem;
|
||||
height: 3px;
|
||||
align-self: center;
|
||||
background: #dde3eb;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--ms1-card);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
padding: 1.75rem 1.5rem 1.5rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.field-label {
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 0.6rem;
|
||||
color: var(--ms1-ink);
|
||||
}
|
||||
|
||||
.field-wrap {
|
||||
position: relative;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.input-vehicule {
|
||||
width: 100%;
|
||||
padding: 1rem 1.15rem;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
letter-spacing: 0.08em;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.input-vehicule:focus {
|
||||
outline: none;
|
||||
border-color: var(--ms1-orange);
|
||||
box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2);
|
||||
}
|
||||
|
||||
.input-lien {
|
||||
width: 100%;
|
||||
padding: 1rem 1.15rem;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.45;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.input-lien:focus {
|
||||
outline: none;
|
||||
border-color: var(--ms1-orange);
|
||||
box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2);
|
||||
}
|
||||
|
||||
.input-lien::placeholder {
|
||||
color: #9aa3af;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.75rem 1rem;
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.btn-enter {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
padding: 0.85rem 1.5rem;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: linear-gradient(180deg, var(--ms1-orange) 0%, var(--ms1-orange-dark) 100%);
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 6px 20px rgba(255, 140, 0, 0.4);
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
|
||||
.btn-enter:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 28px rgba(255, 140, 0, 0.5);
|
||||
}
|
||||
|
||||
.btn-enter:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-ms1 {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.85rem 1.25rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--ms1-ink);
|
||||
background: #fff;
|
||||
border: 2px solid var(--ms1-ink);
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.btn-ms1:hover {
|
||||
background: var(--ms1-ink);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-enter:disabled {
|
||||
opacity: 0.85;
|
||||
cursor: wait;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-enter .key-cap {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 2rem;
|
||||
height: 1.75rem;
|
||||
padding: 0 0.4rem;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
.hint {
|
||||
color: var(--ms1-muted);
|
||||
font-size: 0.9rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.msg {
|
||||
margin: 0 0 1.25rem;
|
||||
padding: 1rem 1.15rem;
|
||||
border-radius: 12px;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
animation: fadeUp 0.35s ease-out;
|
||||
}
|
||||
|
||||
.msg.ok {
|
||||
background: #e6f4ed;
|
||||
color: var(--ms1-ok);
|
||||
border: 1px solid #b8e6d0;
|
||||
}
|
||||
|
||||
.msg.err {
|
||||
background: #fdecea;
|
||||
color: var(--ms1-err);
|
||||
border: 1px solid #f5c4c0;
|
||||
}
|
||||
|
||||
.back {
|
||||
text-align: center;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.back a {
|
||||
color: var(--ms1-muted);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 8px;
|
||||
transition: color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.back a:hover {
|
||||
color: var(--ms1-orange-dark);
|
||||
background: rgba(255, 140, 0, 0.1);
|
||||
}
|
||||
|
||||
.share-box {
|
||||
background: #fff8ee;
|
||||
border: 1px dashed var(--ms1-orange);
|
||||
border-radius: 12px;
|
||||
padding: 1rem 1.15rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.share-box strong {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.share-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.share-url {
|
||||
flex: 1 1 12rem;
|
||||
min-width: 0;
|
||||
padding: 0.55rem 0.65rem;
|
||||
font-size: 0.82rem;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.btn-copy {
|
||||
padding: 0.55rem 1rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: var(--ms1-ink);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-copy:hover { background: #2d2d44; }
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.actions { flex-direction: column; align-items: stretch; }
|
||||
.btn-enter { justify-content: center; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<header class="hero">
|
||||
<div class="qr-icon" aria-hidden="true">
|
||||
<span></span><span></span><span></span>
|
||||
<span></span><span></span><span></span>
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<h1>Code QR</h1>
|
||||
<?php if ($strUserName !== '') { ?>
|
||||
<p class="user-bar">Bonjour <?php echo htmlspecialchars($strUserName, ENT_QUOTES, 'UTF-8'); ?>.</p>
|
||||
<?php } ?>
|
||||
</header>
|
||||
|
||||
<p class="intro">Entrez votre numéro de véhicule. Vous pourrez ainsi changer le lien de votre code QR.</p>
|
||||
|
||||
<?php if ($blnCanShareLink && $strShareUrl !== '') { ?>
|
||||
<div class="share-box">
|
||||
<strong>Lien à envoyer aux autres</strong>
|
||||
<p class="hint" style="margin:0 0 0.65rem;">Chaque personne ouvre ce lien et entre <em>son</em> numéro de véhicule.</p>
|
||||
<div class="share-row">
|
||||
<input type="text" class="share-url" id="share_url" readonly value="<?php echo htmlspecialchars($strShareUrl, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<button type="button" class="btn-copy" id="btn_copy_link">Copier le lien</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="steps" aria-hidden="true">
|
||||
<span class="step <?php echo !$blnShowUrlForm ? 'active' : 'done'; ?>">1</span>
|
||||
<span class="step-line"></span>
|
||||
<span class="step <?php echo $blnShowUrlForm ? 'active' : ''; ?>">2</span>
|
||||
</div>
|
||||
|
||||
<?php if ($strMessage !== '') { ?>
|
||||
<div class="msg <?php echo htmlspecialchars($strMessageClass, ENT_QUOTES, 'UTF-8'); ?>" role="status"><?php
|
||||
echo htmlspecialchars($strMessage, ENT_QUOTES, 'UTF-8');
|
||||
?></div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="card">
|
||||
<?php if (!$blnShowUrlForm) { ?>
|
||||
<form method="post" action="<?php echo $strBaseUrlHtml; ?>" id="frm_load">
|
||||
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($strCsrf, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<input type="hidden" name="action" value="load">
|
||||
<label class="field-label" for="vehicule_no">Numéro de véhicule</label>
|
||||
<div class="field-wrap">
|
||||
<input type="text" inputmode="numeric" pattern="[0-9]+" class="input-vehicule" id="vehicule_no" name="vehicule_no" required autofocus placeholder="ex. 8" value="<?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn-enter">
|
||||
<span class="key-cap">↵</span>
|
||||
<span>Continuer</span>
|
||||
</button>
|
||||
<p class="hint">Remplissez le numéro, puis cliquez ou appuyez sur Entrée.</p>
|
||||
</div>
|
||||
</form>
|
||||
<?php } else { ?>
|
||||
<?php if ($strVehiculeSaisi !== '') { ?>
|
||||
<p class="hint" style="margin:0 0 1rem;">Véhicule <strong><?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?></strong></p>
|
||||
<?php } ?>
|
||||
<form method="post" action="<?php echo $strBaseUrlHtml; ?>" id="frm_save">
|
||||
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($strCsrf, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<input type="hidden" name="action" value="save">
|
||||
<input type="hidden" name="pk" value="<?php echo (int) $intPk; ?>">
|
||||
<input type="hidden" name="vehicule_no" value="<?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<label class="field-label" for="lien_qr">Lien de votre code QR</label>
|
||||
<div class="field-wrap">
|
||||
<input type="url" class="input-lien" id="lien_qr" name="lien_qr" required autofocus placeholder="https://..." value="<?php echo htmlspecialchars($strCurrentHttp, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn-enter">
|
||||
<span class="key-cap">↵</span>
|
||||
<span>Enregistrer</span>
|
||||
</button>
|
||||
<p class="hint">Ou enregistrer directement le lien par défaut :</p>
|
||||
</div>
|
||||
</form>
|
||||
<form method="post" action="<?php echo $strBaseUrlHtml; ?>" style="margin-top:0.75rem;">
|
||||
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($strCsrf, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<input type="hidden" name="action" value="save_ms1">
|
||||
<input type="hidden" name="pk" value="<?php echo (int) $intPk; ?>">
|
||||
<input type="hidden" name="vehicule_no" value="<?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<button type="submit" class="btn-ms1">Mettre le lien vers ms1.ca</button>
|
||||
</form>
|
||||
<p class="hint" style="margin-top:0.75rem;">Sinon modifiez l’adresse ci-dessus et appuyez sur Entrée pour enregistrer.</p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<?php if ($blnShowUrlForm) { ?>
|
||||
<p class="back"><a href="<?php echo $strBaseUrlHtml; ?>">← Autre numéro de véhicule</a></p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php if ($blnCanShareLink && $strShareUrl !== '') { ?>
|
||||
<script>
|
||||
(function () {
|
||||
var btn = document.getElementById('btn_copy_link');
|
||||
var input = document.getElementById('share_url');
|
||||
if (!btn || !input) return;
|
||||
btn.addEventListener('click', function () {
|
||||
input.select();
|
||||
input.setSelectionRange(0, 99999);
|
||||
var ok = false;
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(input.value).then(function () { ok = true; });
|
||||
}
|
||||
try { ok = document.execCommand('copy') || ok; } catch (e) {}
|
||||
btn.textContent = ok ? 'Copié !' : 'Sélectionné — Ctrl+C';
|
||||
setTimeout(function () { btn.textContent = 'Copier le lien'; }, 2000);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?php } ?>
|
||||
</body>
|
||||
</html>
|
||||
@ -2178,10 +2178,14 @@ function fxShowCommandes($arrEpreuvesCommandees, $arrCompteClient, $tep_id, $str
|
||||
<td colspan="7">
|
||||
<div class="h5">
|
||||
<?php
|
||||
$arrCapitaine = fxGetCapitaine($arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['pec_id'], $arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['epr_id']);
|
||||
|
||||
$arrCapitaine = fxGetCapitaine($arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['pec_id'], $arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['epr_id']);
|
||||
//MSIN-4375
|
||||
|
||||
|
||||
echo $arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['par_prenom'] . ' ' . $arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['par_nom'];
|
||||
if ($arrCapitaine != false) {
|
||||
echo $arrCapitaine['par_nom'] . ', ' . $arrCapitaine['par_prenom'];
|
||||
echo 'Capitaine:'.$arrCapitaine['par_nom'] . ', ' . $arrCapitaine['par_prenom'];
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@ -2196,6 +2200,10 @@ function fxShowCommandes($arrEpreuvesCommandees, $arrCompteClient, $tep_id, $str
|
||||
<?php echo fxGetTabInscription('epr_type_' . $strLangue, $arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['epr_id'], 'epreuves', 'epr'); ?>
|
||||
<br>
|
||||
<?php
|
||||
//MSIN-4376
|
||||
//print_rsl($arrEpreuvesCommandees);
|
||||
if($arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['eve_code_qr']!=1 ){
|
||||
|
||||
//MSIN-4323
|
||||
//if($arrEpreuvesCommandees[$intCtrEpreuvesCommandees]['eve_code_qr']==1 ){
|
||||
// print_rsl($arrEpreuvesCommandees[$intCtrEpreuvesCommandees]);
|
||||
@ -2216,7 +2224,7 @@ function fxShowCommandes($arrEpreuvesCommandees, $arrCompteClient, $tep_id, $str
|
||||
?> <img src="<?php echo $vDomaine.'/php/qr_img.php?t='.urlencode($result['qr_public_id']); ?> " width="100" /> <?php
|
||||
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
|
||||
@ -1436,6 +1436,10 @@ function fxListPanier($strNoPanier)
|
||||
// sortir la couleur de l'événement
|
||||
$sqlColor = "SELECT eve_couleur FROM inscriptions_evenements WHERE eve_id = " . intval($intEvenement);
|
||||
$strColor = $objDatabase->fxGetVar($sqlColor);
|
||||
//MSIN-4376
|
||||
// sortir la switch qrcode
|
||||
$sqlqrcode = "SELECT eve_code_qr FROM inscriptions_evenements WHERE eve_id = " . intval($intEvenement);
|
||||
$strqrcode = $objDatabase->fxGetVar($sqlqrcode);
|
||||
|
||||
// si vide, couleur par défaut
|
||||
if (empty($strColor)) {
|
||||
@ -1459,7 +1463,7 @@ function fxListPanier($strNoPanier)
|
||||
$tabRetour[12] = $tabDons;
|
||||
$tabRetour[13] = $tabDonsAuto;
|
||||
$tabRetour[14] = $strColor;
|
||||
|
||||
$tabRetour[15] = $strqrcode;
|
||||
return $tabRetour;
|
||||
}
|
||||
|
||||
@ -1493,6 +1497,7 @@ function fxShowPanier($strNoPanier, $cart, $output, $resume, $strLangue)
|
||||
$tabQuestionsEpreuve = $tabPanier[11];
|
||||
$tabDons = $tabPanier[12];
|
||||
$strColor = $tabPanier[14];
|
||||
$strcodeqr = $tabPanier[15];
|
||||
|
||||
$tabTotal = fxTotalPanier($strNoPanier, $strLangue);
|
||||
|
||||
@ -1895,7 +1900,12 @@ function fxShowPanier($strNoPanier, $cart, $output, $resume, $strLangue)
|
||||
|
||||
|
||||
//MSIN-4323 $tabEvenements['eve_code_qr']==1 &&
|
||||
if( $resume==1){
|
||||
//MSIN-4376
|
||||
|
||||
|
||||
if($strcodeqr!=1 ){
|
||||
|
||||
if( $resume==1){
|
||||
|
||||
|
||||
$result = fxcreer_qr_token([
|
||||
@ -1916,7 +1926,7 @@ function fxShowPanier($strNoPanier, $cart, $output, $resume, $strLangue)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$strRetour .= '</tr>';
|
||||
}
|
||||
|
||||
@ -2550,8 +2550,8 @@ function fxUpdateQuantites($intEpreuve, $intQuantite, $strLangue) {
|
||||
}
|
||||
|
||||
|
||||
// v2
|
||||
function renderBatchConfig($tabBibAssignments, $strLangue = 'fr') {
|
||||
// v2 — options d'ordre batch (table bib_assignements)
|
||||
function renderBatchConfig($tabBibAssignments, $strLangue = 'fr', $isTeamEpreuve = false) {
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
@ -2562,7 +2562,13 @@ function renderBatchConfig($tabBibAssignments, $strLangue = 'fr') {
|
||||
<div class="mb-2">
|
||||
<label>Ordre d’assignation</label>
|
||||
<select class="form-control form-control-sm batch-order">
|
||||
<?php for ($j = 1; $j < count($tabBibAssignments)+1; $j++) { ?>
|
||||
<?php for ($j = 1; $j < count($tabBibAssignments)+1; $j++) {
|
||||
// bib_assignements.ba_equipe = 1 : option équipe seulement (ex. ba_id 5 « Nom d'équipe »)
|
||||
// → masquée sur épreuve solo ; visible sur épreuve équipe (individuel ou 1 équipe = 1 dossard)
|
||||
if ((int)($tabBibAssignments[$j]['ba_equipe'] ?? 0) === 1 && !$isTeamEpreuve) {
|
||||
continue;
|
||||
}
|
||||
?>
|
||||
<option value="<?php echo $tabBibAssignments[$j]['ba_id']; ?>">
|
||||
<?php echo $tabBibAssignments[$j]['ba_nom_' . $strLangue]; ?>
|
||||
</option>
|
||||
@ -2630,14 +2636,16 @@ function fxShowBibTool4($str_code, $int_eve_id, $strLangue){
|
||||
|
||||
$tabBibStats=fxInfosBibRange(intval($tabEpreuves[$i]['epr_id']));
|
||||
$infoBib = fxInfosBibEpreuve(intval($tabEpreuves[$i]['epr_id']));
|
||||
|
||||
|
||||
|
||||
// MSIN-4379 — Étape 2 : détecte si l'auto est actif (au moins une séquence epr_bib_auto=1).
|
||||
// Prochain tour : étape 6–7 (assignation à l'achat).
|
||||
$blnAutoActive = fxIsBibAutoActive((int)$tabEpreuves[$i]['epr_id']);
|
||||
|
||||
?>
|
||||
|
||||
<div class="epr-row <?php echo $strClass ?>"
|
||||
data-epr-id="<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>">
|
||||
<?php /* MSIN-4379 — Étape 2 : attributs/data pour l'état auto au chargement de la page. */ ?>
|
||||
<div class="epr-row <?php echo $strClass ?><?php echo $blnAutoActive ? ' auto-enabled' : ''; ?>"
|
||||
data-epr-id="<?php echo (int)$tabEpreuves[$i]['epr_id']; ?>"
|
||||
data-auto-active="<?php echo $blnAutoActive ? '1' : '0'; ?>">
|
||||
<!-- GAUCHE -->
|
||||
<div class="epr-block">
|
||||
<div class="epr-header">Épreuve</div>
|
||||
@ -2693,7 +2701,7 @@ if ($teamMode <= 0) {
|
||||
<?php echo ($lockTeamMode ? 'disabled' : ''); ?>
|
||||
<?php echo ($teamMode === 1 ? 'checked' : ''); ?>>
|
||||
|
||||
<span>1 équipe = 1 dossard</span>
|
||||
<span>Dossards individuels</span>
|
||||
</label>
|
||||
|
||||
<label class="team-mode-option">
|
||||
@ -2703,13 +2711,10 @@ if ($teamMode <= 0) {
|
||||
<?php echo ($lockTeamMode ? 'disabled' : ''); ?>
|
||||
<?php echo ($teamMode === 3 ? 'checked' : ''); ?>>
|
||||
|
||||
<span>Ignorer les équipes</span>
|
||||
<span>1 équipe = 1 dossard</span>
|
||||
</label>
|
||||
|
||||
<label class="team-mode-option disabled">
|
||||
<input type="radio" disabled>
|
||||
<span>Dossards individuels par équipe<br>(bientôt)</span>
|
||||
</label>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@ -2783,11 +2788,32 @@ if ($teamMode <= 0) {
|
||||
style="<?php echo ((int)$infoBib['avec_bib'] > 0 ? '' : 'display:none;'); ?>">
|
||||
Réinitialiser
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary btn-auto">Activer automatique</button>
|
||||
<?php /* MSIN-4379 — Étape 2 : boutons et bloc UI pour configurer l'assignation auto (sans assigner encore). */ ?>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-auto <?php echo $blnAutoActive ? 'btn-success' : 'btn-secondary'; ?>">
|
||||
<?php echo $blnAutoActive ? 'Configurer automatique' : 'Activer automatique'; ?>
|
||||
</button>
|
||||
<span class="bib-auto-badge badge badge-success ml-1"
|
||||
style="<?php echo $blnAutoActive ? '' : 'display:none;'; ?>">Auto actif</span>
|
||||
|
||||
<div class="auto-config-container" style="display:none;">
|
||||
<div class="auto-info text-muted small mb-2">
|
||||
Sélectionnez les séquences utilisées à l'inscription.
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-success btn-accepter-auto">Accepter</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary btn-annuler-auto">Annuler</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-danger btn-desactiver-auto"
|
||||
style="<?php echo $blnAutoActive ? '' : 'display:none;'; ?>">
|
||||
Désactiver automatique
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="batch-config-container" style="display:none;">
|
||||
<?php echo renderBatchConfig($tabBibAssignments, $strLangue); ?>
|
||||
<?php
|
||||
// 3e arg. : epr_equipe = 1 → afficher aussi les tris « équipe » (ba_equipe = 1 dans bib_assignements)
|
||||
echo renderBatchConfig($tabBibAssignments, $strLangue, (int)$tabEpreuves[$i]['epr_equipe'] === 1);
|
||||
?>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-secondary btn-simuler-batch" style="display:none;">
|
||||
Simuler
|
||||
@ -2834,6 +2860,7 @@ function fxInfosBibRange($epr_id = 0, $epr_bib_id = 0){
|
||||
b.epr_id,
|
||||
b.epr_bib_start,
|
||||
b.epr_bib_finish,
|
||||
b.epr_bib_auto, /* MSIN-4379 — Étape 1 : flag par séquence (pool auto). */
|
||||
|
||||
COUNT(p.no_bib) AS nb_utilises,
|
||||
MAX(p.no_bib) AS dernier_bib,
|
||||
@ -2929,13 +2956,100 @@ function fxInfosBibRange($epr_id = 0, $epr_bib_id = 0){
|
||||
b.epr_bib_id,
|
||||
b.epr_id,
|
||||
b.epr_bib_start,
|
||||
b.epr_bib_finish
|
||||
b.epr_bib_finish,
|
||||
b.epr_bib_auto
|
||||
|
||||
ORDER BY b.epr_bib_start
|
||||
";
|
||||
|
||||
return $objDatabase->fxGetResults($sqlBibStats);
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4379 — Étape 2
|
||||
* Indique si l'assignation automatique est active pour une épreuve
|
||||
* (au moins une ligne epr_bib_auto = 1 dans inscriptions_epreuves_bib).
|
||||
* Prochain tour : étape 6–7 (lecture de ce flag à l'inscription).
|
||||
*/
|
||||
function fxIsBibAutoActive($epr_id) {
|
||||
global $objDatabase;
|
||||
|
||||
$epr_id = intval($epr_id);
|
||||
|
||||
if ($epr_id <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT COUNT(*)
|
||||
FROM inscriptions_epreuves_bib
|
||||
WHERE epr_id = $epr_id
|
||||
AND epr_bib_auto = 1
|
||||
";
|
||||
|
||||
return (int)$objDatabase->fxGetVar($sql) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4379 — Étape 2
|
||||
* Enregistre la config auto : remet toutes les séquences à 0, puis marque
|
||||
* epr_bib_auto = 1 sur les epr_bib_id choisis. Si $active = false, tout désactive.
|
||||
* Prochain tour : étape 6 lira ces séquences pour fxAssignAutoBibForParticipant().
|
||||
*/
|
||||
function fxSaveBibAutoConfig($epr_id, $ranges, $active = true) {
|
||||
global $objDatabase;
|
||||
|
||||
$epr_id = intval($epr_id);
|
||||
$active = (bool)$active;
|
||||
|
||||
if ($epr_id <= 0) {
|
||||
return ['success' => false, 'message' => 'epr_id invalide'];
|
||||
}
|
||||
|
||||
$objDatabase->fxQuery("
|
||||
UPDATE inscriptions_epreuves_bib
|
||||
SET epr_bib_auto = 0
|
||||
WHERE epr_id = $epr_id
|
||||
");
|
||||
|
||||
if (!$active) {
|
||||
return ['success' => true, 'auto_active' => false];
|
||||
}
|
||||
|
||||
if (empty($ranges) || !is_array($ranges)) {
|
||||
return ['success' => false, 'message' => 'Aucune séquence sélectionnée'];
|
||||
}
|
||||
|
||||
$ids = array_values(array_filter(array_map('intval', $ranges)));
|
||||
|
||||
if (empty($ids)) {
|
||||
return ['success' => false, 'message' => 'Aucune séquence sélectionnée'];
|
||||
}
|
||||
|
||||
$strIds = implode(',', $ids);
|
||||
|
||||
$sqlCheck = "
|
||||
SELECT COUNT(*)
|
||||
FROM inscriptions_epreuves_bib
|
||||
WHERE epr_id = $epr_id
|
||||
AND epr_bib_id IN ($strIds)
|
||||
";
|
||||
$nbValid = (int)$objDatabase->fxGetVar($sqlCheck);
|
||||
|
||||
if ($nbValid !== count($ids)) {
|
||||
return ['success' => false, 'message' => 'Séquences invalides pour cette épreuve'];
|
||||
}
|
||||
|
||||
$objDatabase->fxQuery("
|
||||
UPDATE inscriptions_epreuves_bib
|
||||
SET epr_bib_auto = 1
|
||||
WHERE epr_id = $epr_id
|
||||
AND epr_bib_id IN ($strIds)
|
||||
");
|
||||
|
||||
return ['success' => true, 'auto_active' => true];
|
||||
}
|
||||
|
||||
function fxInfosBibEpreuve($epr_id){
|
||||
global $objDatabase;
|
||||
|
||||
@ -2961,11 +3075,14 @@ function fxInfosBibEpreuve($epr_id){
|
||||
|
||||
$row = $objDatabase->fxGetRow($sql);
|
||||
|
||||
return [
|
||||
$info = [
|
||||
'total' => (int)($row['total'] ?? 0),
|
||||
'avec_bib' => (int)($row['avec_bib'] ?? 0),
|
||||
'sans_bib' => (int)($row['sans_bib'] ?? 0)
|
||||
'sans_bib' => (int)($row['sans_bib'] ?? 0),
|
||||
'a_assigner' => fxCountBatchAssignUnits($epr_id)
|
||||
];
|
||||
|
||||
return $info;
|
||||
}
|
||||
function renderBibRanges($tabBibRanges, $epr_id = 0, $mode = 'assign') {
|
||||
//print_rsl($tabBibRanges);
|
||||
@ -3065,12 +3182,22 @@ if (
|
||||
$showCheckbox = true;
|
||||
}
|
||||
|
||||
// MSIN-4379 — Étape 2 : mode « auto » — checkbox sur chaque séquence enregistrée.
|
||||
if (
|
||||
$mode === 'auto'
|
||||
&& (int)$range['epr_bib_id'] > 0
|
||||
) {
|
||||
$showCheckbox = true;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<?php if ($showCheckbox) { ?>
|
||||
<input type="checkbox"
|
||||
class="batch-select-range"
|
||||
data-range-id="<?php echo (int)$range['epr_bib_id']; ?>">
|
||||
data-range-id="<?php echo (int)$range['epr_bib_id']; ?>"
|
||||
<?php /* MSIN-4379 — Étape 2 : pré-cocher les séquences déjà en epr_bib_auto = 1. */ ?>
|
||||
<?php if ($mode === 'auto' && (int)($range['epr_bib_auto'] ?? 0) === 1) { ?>checked<?php } ?>>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
@ -3238,11 +3365,12 @@ if ($title != '') {
|
||||
|
||||
<div>Participant</div>
|
||||
|
||||
<?php if ((int)$tabEpreuve['epr_equipe'] === 1) { ?>
|
||||
<div>Équipe</div>
|
||||
<?php } ?>
|
||||
<?php if ((int)$tabEpreuve['epr_equipe'] === 1) { ?>
|
||||
<div>No équipe</div>
|
||||
<div>Équipe</div>
|
||||
<?php } ?>
|
||||
|
||||
<div>Numéro du participant</div>
|
||||
<div>Dossard</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -3276,14 +3404,20 @@ if ($title != '') {
|
||||
</div>
|
||||
<?php if ((int)$tabEpreuve['epr_equipe'] === 1) { ?>
|
||||
|
||||
<div class="bib-view-team-number">
|
||||
<?php
|
||||
echo $p['no_equipe'];
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="bib-view-team">
|
||||
|
||||
<?php
|
||||
echo $p['pec_nom_equipe'];
|
||||
echo $p['pec_nom_equipe'];
|
||||
|
||||
if ((int)$p['rol_id'] === 1) {
|
||||
echo ' (C)';
|
||||
}
|
||||
if ((int)$p['rol_id'] === 1) {
|
||||
echo ' (C)';
|
||||
}
|
||||
?>
|
||||
|
||||
</div>
|
||||
@ -3334,7 +3468,8 @@ function fxGetParticipantsForBatchAssign($epr_id, $ba_id) {
|
||||
|
||||
// =====================
|
||||
// RÉCUPÉRER L'ORDER BY DYNAMIQUE
|
||||
// Source : table bib_assignements
|
||||
// Source : bib_assignements.ba_sql_order (choix du promoteur dans le batch)
|
||||
// Ex. ba_id 5 : TRIM(c.pec_nom_equipe), p.par_nom, p.par_prenom
|
||||
// =====================
|
||||
$sqlOrder = "
|
||||
SELECT ba_sql_order
|
||||
@ -3355,21 +3490,33 @@ function fxGetParticipantsForBatchAssign($epr_id, $ba_id) {
|
||||
}
|
||||
|
||||
// =====================
|
||||
// PARTICIPANTS SOLO À ASSIGNER
|
||||
// Important :
|
||||
// PARTICIPANTS À ASSIGNER (solo et équipe)
|
||||
// - jointure c.* requise pour les tris par nom d'équipe (pec_nom_equipe)
|
||||
// - on ne prend que ceux sans no_bib
|
||||
// - on exclut rol_id 3 et 4 comme dans l'ancien code
|
||||
// - aucune écriture DB ici
|
||||
// =====================
|
||||
$sql = "
|
||||
SELECT p.*
|
||||
FROM resultats_participants p
|
||||
WHERE p.epr_id = $epr_id
|
||||
AND p.is_cancelled = 0
|
||||
AND (p.no_bib IS NULL OR p.no_bib = '' OR p.no_bib = 0)
|
||||
AND p.rol_id NOT IN (3, 4)
|
||||
ORDER BY $orderBy
|
||||
";
|
||||
$sql = "
|
||||
SELECT
|
||||
p.*,
|
||||
p.pec_id,
|
||||
c.pec_id_original,
|
||||
c.pec_nom_equipe,
|
||||
c.no_equipe,
|
||||
ie.epr_bib_team_mode
|
||||
FROM resultats_participants p
|
||||
|
||||
LEFT JOIN resultats_epreuves_commandees c
|
||||
ON c.pec_id_original = p.pec_id
|
||||
AND c.epr_id = p.epr_id
|
||||
LEFT JOIN inscriptions_epreuves ie
|
||||
ON ie.epr_id = p.epr_id
|
||||
WHERE p.epr_id = $epr_id
|
||||
AND p.is_cancelled = 0
|
||||
AND (p.no_bib IS NULL OR p.no_bib = '' OR p.no_bib = 0)
|
||||
AND p.rol_id NOT IN (3, 4)
|
||||
|
||||
ORDER BY $orderBy
|
||||
";
|
||||
|
||||
return $objDatabase->fxGetResults($sql);
|
||||
}
|
||||
@ -3418,6 +3565,7 @@ function fxGetRangesForBatchAssign($epr_id, $ranges) {
|
||||
// =====================
|
||||
$out = [];
|
||||
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $r) {
|
||||
|
||||
$start = (int)$r['epr_bib_start'];
|
||||
@ -3432,6 +3580,7 @@ function fxGetRangesForBatchAssign($epr_id, $ranges) {
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
@ -3480,127 +3629,335 @@ function fxGetNextAvailableBib($epr_id, $tabRanges) {
|
||||
// 👉 aucun BIB disponible
|
||||
return null;
|
||||
}
|
||||
function fxProcessBatchAssignments($epr_id, $participants, $tabRanges, $mode = 'simulation') {
|
||||
function fxLoadUsedBibsForBatch($epr_id) {
|
||||
global $objDatabase;
|
||||
|
||||
$assignments = [];
|
||||
|
||||
if (empty($participants) || empty($tabRanges)) {
|
||||
return $assignments;
|
||||
}
|
||||
|
||||
$epr_id = intval($epr_id);
|
||||
|
||||
// =====================
|
||||
// MODE SIMULATION → cache en mémoire
|
||||
// MODE EXECUTE → on ne fait PAS confiance au cache
|
||||
// =====================
|
||||
$usedBib = [];
|
||||
$sql = "
|
||||
SELECT no_bib
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = " . intval($epr_id) . "
|
||||
AND no_bib IS NOT NULL
|
||||
AND no_bib != ''
|
||||
AND no_bib > 0
|
||||
";
|
||||
$rows = $objDatabase->fxGetResults($sql);
|
||||
|
||||
if ($mode === 'simulation') {
|
||||
|
||||
// Charger les BIB déjà utilisés (1 seule fois)
|
||||
$sql = "
|
||||
SELECT no_bib
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = $epr_id
|
||||
AND no_bib IS NOT NULL
|
||||
AND no_bib != ''
|
||||
";
|
||||
|
||||
$rows = $objDatabase->fxGetResults($sql);
|
||||
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $r) {
|
||||
$usedBib[(int)$r['no_bib']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// =====================
|
||||
// BOUCLE PRINCIPALE
|
||||
// =====================
|
||||
foreach ($participants as $p) {
|
||||
return $usedBib;
|
||||
}
|
||||
|
||||
$par_id = (int)$p['par_id'];
|
||||
$foundBib = null;
|
||||
/**
|
||||
* Cherche le prochain dossard libre dans les séquences sélectionnées.
|
||||
*
|
||||
* Règle anti-doublon (mode execute / GO) :
|
||||
* - solo ou équipe « dossards individuels » : un numéro = une personne (COUNT participants)
|
||||
* - équipe « 1 équipe = 1 dossard » : un numéro = une équipe (COUNT DISTINCT pec_id)
|
||||
* → plusieurs coéquipiers peuvent partager le même no_bib
|
||||
*
|
||||
* @param int $teamMode epr_bib_team_mode (1 = individuel, 3 = 1 équipe = 1 dossard)
|
||||
*/
|
||||
function fxFindNextBatchBib($epr_id, $tabRanges, $mode, &$usedBib, $teamMode = 1) {
|
||||
global $objDatabase;
|
||||
|
||||
// =====================
|
||||
// CHERCHER BIB LIBRE
|
||||
// =====================
|
||||
foreach ($tabRanges as $range) {
|
||||
$epr_id = intval($epr_id);
|
||||
$teamMode = (int)$teamMode;
|
||||
|
||||
$start = (int)$range['start'];
|
||||
$end = (int)$range['end'];
|
||||
foreach ($tabRanges as $range) {
|
||||
$start = (int)$range['start'];
|
||||
$end = (int)$range['end'];
|
||||
|
||||
for ($i = $start; $i <= $end; $i++) {
|
||||
|
||||
// =====================
|
||||
// SIMULATION
|
||||
// =====================
|
||||
if ($mode === 'simulation') {
|
||||
|
||||
if (!isset($usedBib[$i])) {
|
||||
$foundBib = $i;
|
||||
$usedBib[$i] = true; // réserver
|
||||
break 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
// =====================
|
||||
// EXECUTE (sécurisé DB)
|
||||
// =====================
|
||||
$sqlCheck = "
|
||||
SELECT COUNT(*)
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = $epr_id
|
||||
AND no_bib = $i
|
||||
";
|
||||
|
||||
$exists = (int)$objDatabase->fxGetVar($sqlCheck);
|
||||
|
||||
if ($exists === 0) {
|
||||
$foundBib = $i;
|
||||
|
||||
// ÉCRITURE RÉELLE
|
||||
$sqlUpdate = "
|
||||
UPDATE resultats_participants
|
||||
SET no_bib = $i,
|
||||
par_date_bib = IFNULL(par_date_bib, NOW())
|
||||
WHERE par_id = $par_id
|
||||
AND is_cancelled = 0
|
||||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||||
";
|
||||
|
||||
$objDatabase->fxQuery($sqlUpdate);
|
||||
|
||||
break 2;
|
||||
}
|
||||
for ($i = $start; $i <= $end; $i++) {
|
||||
if ($mode === 'simulation') {
|
||||
// Simulation : cache mémoire (même logique solo/équipe via $teamBibMap en amont)
|
||||
if (!isset($usedBib[$i])) {
|
||||
$usedBib[$i] = true;
|
||||
return $i;
|
||||
}
|
||||
} elseif ($teamMode === 3) {
|
||||
// GO — mode « 1 équipe = 1 dossard »
|
||||
// Le numéro est libre s'il n'est pas déjà pris par une autre équipe.
|
||||
$sqlCheck = "
|
||||
SELECT COUNT(DISTINCT pec_id)
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = $epr_id
|
||||
AND no_bib = $i
|
||||
AND is_cancelled = 0
|
||||
AND pec_id > 0
|
||||
";
|
||||
if ((int)$objDatabase->fxGetVar($sqlCheck) === 0) {
|
||||
return $i;
|
||||
}
|
||||
} else {
|
||||
// GO — solo ou dossards individuels : un numéro ne peut servir qu'à une personne
|
||||
$sqlCheck = "
|
||||
SELECT COUNT(*)
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = $epr_id
|
||||
AND no_bib = $i
|
||||
AND is_cancelled = 0
|
||||
";
|
||||
if ((int)$objDatabase->fxGetVar($sqlCheck) === 0) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Écrit le no_bib d'un participant (batch GO).
|
||||
* Note : en mode « 1 équipe = 1 dossard », plusieurs lignes peuvent légitimement
|
||||
* recevoir le même no_bib — ce n'est pas un doublon erroné.
|
||||
*/
|
||||
function fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib) {
|
||||
global $objDatabase;
|
||||
|
||||
$sqlUpdate = "
|
||||
UPDATE resultats_participants
|
||||
SET no_bib = " . intval($foundBib) . ",
|
||||
par_date_bib = IFNULL(par_date_bib, NOW())
|
||||
WHERE par_id = " . intval($par_id) . "
|
||||
AND is_cancelled = 0
|
||||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||||
";
|
||||
|
||||
$objDatabase->fxQuery($sqlUpdate);
|
||||
}
|
||||
|
||||
function fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, &$updatedTeams) {
|
||||
global $objDatabase;
|
||||
|
||||
if ($teamKey <= 0 || $teamNumber <= 0 || isset($updatedTeams[$teamKey])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sqlTeam = "
|
||||
UPDATE resultats_epreuves_commandees
|
||||
SET no_equipe = " . intval($teamNumber) . "
|
||||
WHERE pec_id_original = " . intval($teamKey) . "
|
||||
AND epr_id = " . intval($epr_id) . "
|
||||
";
|
||||
|
||||
$objDatabase->fxQuery($sqlTeam);
|
||||
$updatedTeams[$teamKey] = true;
|
||||
}
|
||||
|
||||
function fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber) {
|
||||
return [
|
||||
'rol_id' => $p['rol_id'],
|
||||
'par_id' => (int)$p['par_id'],
|
||||
'par_prenom' => $p['par_prenom'],
|
||||
'par_nom' => $p['par_nom'],
|
||||
'no_bib' => $foundBib,
|
||||
'no_equipe' => $teamNumber,
|
||||
'pec_nom_equipe' => $p['pec_nom_equipe'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
function fxGetBatchTeamKey($p) {
|
||||
return (int)($p['pec_id_original'] ?? $p['pec_id'] ?? 0);
|
||||
}
|
||||
|
||||
function fxCountBatchAssignUnits($epr_id, $participants = null) {
|
||||
global $objDatabase;
|
||||
|
||||
$epr_id = intval($epr_id);
|
||||
|
||||
if ($epr_id <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sqlEpreuve = "
|
||||
SELECT epr_equipe, epr_bib_team_mode
|
||||
FROM inscriptions_epreuves
|
||||
WHERE epr_id = $epr_id
|
||||
LIMIT 1
|
||||
";
|
||||
$tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve);
|
||||
|
||||
$countParticipants = function ($rows) {
|
||||
return is_array($rows) ? count($rows) : 0;
|
||||
};
|
||||
|
||||
if (!$tabEpreuve || (int)$tabEpreuve['epr_equipe'] !== 1) {
|
||||
if (is_array($participants)) {
|
||||
return $countParticipants($participants);
|
||||
}
|
||||
|
||||
return (int)$objDatabase->fxGetVar("
|
||||
SELECT COUNT(*)
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = $epr_id
|
||||
AND is_cancelled = 0
|
||||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||||
AND rol_id NOT IN (3, 4)
|
||||
");
|
||||
}
|
||||
|
||||
$teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1);
|
||||
if ($teamMode <= 0) {
|
||||
$teamMode = 1;
|
||||
}
|
||||
|
||||
if ($teamMode !== 3) {
|
||||
if (is_array($participants)) {
|
||||
return $countParticipants($participants);
|
||||
}
|
||||
|
||||
return (int)$objDatabase->fxGetVar("
|
||||
SELECT COUNT(*)
|
||||
FROM resultats_participants
|
||||
WHERE epr_id = $epr_id
|
||||
AND is_cancelled = 0
|
||||
AND (no_bib IS NULL OR no_bib = '' OR no_bib = 0)
|
||||
AND rol_id NOT IN (3, 4)
|
||||
");
|
||||
}
|
||||
|
||||
if (is_array($participants)) {
|
||||
$teams = [];
|
||||
|
||||
foreach ($participants as $p) {
|
||||
$teamKey = fxGetBatchTeamKey($p);
|
||||
|
||||
if ($teamKey > 0) {
|
||||
$teams[$teamKey] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return count($teams);
|
||||
}
|
||||
|
||||
return (int)$objDatabase->fxGetVar("
|
||||
SELECT COUNT(DISTINCT p.pec_id)
|
||||
FROM resultats_participants p
|
||||
WHERE p.epr_id = $epr_id
|
||||
AND p.is_cancelled = 0
|
||||
AND (p.no_bib IS NULL OR p.no_bib = '' OR p.no_bib = 0)
|
||||
AND p.rol_id NOT IN (3, 4)
|
||||
AND p.pec_id > 0
|
||||
");
|
||||
}
|
||||
|
||||
function fxProcessBatchAssignmentsSolo($epr_id, $participants, $tabRanges, $mode = 'simulation') {
|
||||
$assignments = [];
|
||||
$usedBib = ($mode === 'simulation') ? fxLoadUsedBibsForBatch($epr_id) : [];
|
||||
|
||||
foreach ($participants as $p) {
|
||||
$foundBib = fxFindNextBatchBib($epr_id, $tabRanges, $mode, $usedBib);
|
||||
|
||||
// =====================
|
||||
// PLUS DE PLACE → STOP
|
||||
// =====================
|
||||
if ($foundBib === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// STOCKER LE RÉSULTAT
|
||||
// =====================
|
||||
$assignments[] = [
|
||||
'par_id' => $par_id,
|
||||
'par_prenom' => $p['par_prenom'],
|
||||
'par_nom' => $p['par_nom'],
|
||||
'no_bib' => $foundBib
|
||||
];
|
||||
if ($mode === 'execute') {
|
||||
fxApplyBatchParticipantBib($epr_id, (int)$p['par_id'], $foundBib);
|
||||
}
|
||||
|
||||
$assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, 0);
|
||||
}
|
||||
|
||||
return $assignments;
|
||||
}
|
||||
function fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants) {
|
||||
|
||||
$nbParticipants = count($participants);
|
||||
function fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mode, $teamMode) {
|
||||
global $objDatabase;
|
||||
|
||||
$assignments = [];
|
||||
$teamMap = [];
|
||||
$updatedTeams = [];
|
||||
// Mode 3 : mémorise le dossard déjà choisi pour chaque équipe (pec_id)
|
||||
// → les coéquipiers réutilisent ce numéro sans repasser par fxFindNextBatchBib
|
||||
$teamBibMap = [];
|
||||
$nextTeamNumber = 1;
|
||||
$usedBib = ($mode === 'simulation') ? fxLoadUsedBibsForBatch($epr_id) : [];
|
||||
|
||||
foreach ($participants as $p) {
|
||||
$par_id = (int)$p['par_id'];
|
||||
$teamKey = fxGetBatchTeamKey($p);
|
||||
$teamNumber = 0;
|
||||
$foundBib = null;
|
||||
|
||||
if ($teamMode === 3 && $teamKey > 0 && isset($teamBibMap[$teamKey])) {
|
||||
// Coéquipier suivant : même dossard que le premier membre déjà traité
|
||||
$foundBib = $teamBibMap[$teamKey];
|
||||
$teamNumber = $foundBib;
|
||||
} elseif ($teamMode !== 3 && $teamKey > 0) {
|
||||
// Mode dossards individuels : no_equipe séquentiel (1, 2, 3…) partagé par l'équipe
|
||||
if (!isset($teamMap[$teamKey])) {
|
||||
$teamMap[$teamKey] = $nextTeamNumber;
|
||||
$nextTeamNumber++;
|
||||
}
|
||||
|
||||
$teamNumber = $teamMap[$teamKey];
|
||||
}
|
||||
|
||||
if ($foundBib === null) {
|
||||
// Premier membre d'une équipe (mode 3) ou chaque participant (mode 1)
|
||||
$foundBib = fxFindNextBatchBib($epr_id, $tabRanges, $mode, $usedBib, $teamMode);
|
||||
}
|
||||
|
||||
if ($foundBib === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($teamMode === 3 && $teamKey > 0) {
|
||||
$teamBibMap[$teamKey] = $foundBib;
|
||||
$teamNumber = $foundBib;
|
||||
}
|
||||
|
||||
if ($mode === 'execute') {
|
||||
fxApplyBatchParticipantBib($epr_id, $par_id, $foundBib);
|
||||
fxApplyBatchTeamNumber($epr_id, $teamKey, $teamNumber, $updatedTeams);
|
||||
}
|
||||
|
||||
$assignments[] = fxBuildBatchAssignmentRow($p, $foundBib, $teamNumber);
|
||||
}
|
||||
|
||||
return $assignments;
|
||||
}
|
||||
|
||||
function fxProcessBatchAssignments($epr_id, $participants, $tabRanges, $mode = 'simulation') {
|
||||
global $objDatabase;
|
||||
|
||||
if (empty($participants) || empty($tabRanges)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$epr_id = intval($epr_id);
|
||||
$sqlEpreuve = "
|
||||
SELECT epr_equipe, epr_bib_team_mode
|
||||
FROM inscriptions_epreuves
|
||||
WHERE epr_id = $epr_id
|
||||
LIMIT 1
|
||||
";
|
||||
$tabEpreuve = $objDatabase->fxGetRow($sqlEpreuve);
|
||||
|
||||
// Épreuves solo : logique simple, inchangée (1 personne = 1 dossard)
|
||||
if (!$tabEpreuve || (int)$tabEpreuve['epr_equipe'] !== 1) {
|
||||
return fxProcessBatchAssignmentsSolo($epr_id, $participants, $tabRanges, $mode);
|
||||
}
|
||||
|
||||
// Épreuves équipe uniquement — voir fxProcessBatchAssignmentsEquipe()
|
||||
$teamMode = (int)($tabEpreuve['epr_bib_team_mode'] ?? 1);
|
||||
if ($teamMode <= 0) {
|
||||
$teamMode = 1;
|
||||
}
|
||||
|
||||
return fxProcessBatchAssignmentsEquipe($epr_id, $participants, $tabRanges, $mode, $teamMode);
|
||||
}
|
||||
|
||||
function fxBuildBatchSummaryFromRanges($tabRangesInfos, $participants, $epr_id = 0) {
|
||||
|
||||
$nbParticipants = fxCountBatchAssignUnits($epr_id, $participants);
|
||||
$nbDispo = 0;
|
||||
|
||||
if (!empty($tabRangesInfos)) {
|
||||
@ -3676,3 +4033,45 @@ function fxGetParticipantsForBatchReset($epr_id, $ranges) {
|
||||
return $objDatabase->fxGetResults($sql);
|
||||
}
|
||||
|
||||
function fxResolveTeamBib(
|
||||
$p,
|
||||
&$teamBibMap,
|
||||
$epr_id
|
||||
) {
|
||||
global $objDatabase;
|
||||
|
||||
$teamKey = (int)($p['pec_id'] ?? 0);
|
||||
|
||||
if ($teamKey <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// MÉMOIRE
|
||||
// =====================
|
||||
if (isset($teamBibMap[$teamKey])) {
|
||||
return $teamBibMap[$teamKey];
|
||||
}
|
||||
|
||||
// =====================
|
||||
// DB EXISTANTE
|
||||
// =====================
|
||||
$sql = "
|
||||
SELECT no_equipe
|
||||
FROM resultats_epreuves_commandees
|
||||
WHERE pec_id_original = $teamKey
|
||||
AND epr_id = " . intval($epr_id) . "
|
||||
LIMIT 1
|
||||
";
|
||||
|
||||
$existingBib = (int)$objDatabase->fxGetVar($sql);
|
||||
|
||||
if ($existingBib > 0) {
|
||||
|
||||
$teamBibMap[$teamKey] = $existingBib;
|
||||
|
||||
return $existingBib;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -7,10 +7,17 @@
|
||||
* Constantes *
|
||||
*
|
||||
**************/
|
||||
define('_VERSION_CODE', '4.72.39');
|
||||
define('_DATE_CODE', '2026-03-09');
|
||||
define('_VERSION_CODE', '4.72.60');
|
||||
define('_DATE_CODE', '2026-06-02');
|
||||
//MSIN-4290
|
||||
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
|
||||
// Outil temporaire ms1_kc_set.php — modifier key_chain_http (lien /kc/{pk}/)
|
||||
// KEYCHAIN_HTTP_EDIT_SECRET : paramètre ?k= dans l’URL (mot de passe d’accès à la page)
|
||||
// KEYCHAIN_HTTP_EDIT_SHIFT : ajouté au numéro saisi (ex. 8 → pk 108 en base)
|
||||
// KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS : com_id autorisés (virgules) pour /ms1_kc_set.php sans ?k=
|
||||
define('KEYCHAIN_HTTP_EDIT_SECRET', 'ms1_kc_http_edit_2026_c7e4a91f3b2d8e0f6a5c4b3d2e1f0a9');
|
||||
define('KEYCHAIN_HTTP_EDIT_SHIFT', 100);
|
||||
define('KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS', '');
|
||||
|
||||
/**********************
|
||||
*
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
// IMPORTANT : aucun espace avant <?php
|
||||
// Aucun echo avant les headers
|
||||
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('display_startup_errors', 0);
|
||||
error_reporting(E_ALL);
|
||||
require_once __DIR__ . '/../libs/phpqrcode-master/qrlib.php';
|
||||
|
||||
// Vérification du token
|
||||
|
||||
20
qr_test.php
20
qr_test.php
@ -175,7 +175,27 @@ function fxShowQrParticipantDebug($strToken, $strLangue = 'fr')
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
============================================
|
||||
DEBUG PARTICIPANT
|
||||
============================================
|
||||
*/
|
||||
|
||||
$strRetour .= '
|
||||
<pre style="
|
||||
background:#111;
|
||||
color:#0f0;
|
||||
padding:15px;
|
||||
font-size:12px;
|
||||
overflow:auto;
|
||||
margin-top:15px;
|
||||
">';
|
||||
|
||||
$strRetour .= htmlspecialchars(
|
||||
print_r($tabParticipantTrouve, true)
|
||||
);
|
||||
|
||||
$strRetour .= '</pre>';
|
||||
return $strRetour;
|
||||
}
|
||||
/*
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
global $db, $objDatabase, $vblnEnvironementDev, $vDomaine, $objDatabasePreProd, $objDatabaseProd;
|
||||
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('display_startup_errors', 0);
|
||||
error_reporting(E_ALL);
|
||||
// vérifier les paramètres
|
||||
if (!empty($_GET['t']))
|
||||
$intMenu = $_GET['t'];
|
||||
|
||||
@ -7,7 +7,7 @@ require_once('inc_dates.php');
|
||||
require_once('inc_files.php');
|
||||
require_once('inc_manager.php');
|
||||
error_reporting(E_ALL);
|
||||
//ini_set("display_errors", 0);
|
||||
ini_set("display_errors", 0);
|
||||
global $arrConDatabasePreProd,$arrConDatabasecrm;
|
||||
$db = $objDatabase = new clsMysql($GLOBALS['arrConDatabaseMain']);
|
||||
$db_prod = $objDatabaseProd = new clsMysql($GLOBALS['arrConDatabaseProd']);
|
||||
|
||||
@ -600,6 +600,9 @@ function fxrapportexcell_array($headers,$data,$memexcfichier,$memexctitre) {
|
||||
}
|
||||
function fxupload_excel_fnq($mem_fichier) {
|
||||
/** Include PHPExcel */
|
||||
//ini_set('display_errors', 1);
|
||||
//ini_set('display_startup_errors', 1);
|
||||
//error_reporting(E_ALL);
|
||||
require_once dirname(__FILE__) . '/Classes/PHPExcel.php';
|
||||
$objReader = new PHPExcel_Reader_Excel2007();
|
||||
$objReader->setReadDataOnly(false);
|
||||
@ -621,13 +624,14 @@ function fxupload_excel_fnq($mem_fichier) {
|
||||
$counter = 0;
|
||||
//echo('test');
|
||||
foreach ($mem_rows as $r) {
|
||||
|
||||
//echosl($counter);
|
||||
if ($counter != 0) {
|
||||
// $sqlInsert = "INSERT INTO inscriptions_tq set tq_nom='" . $GLOBALS['db']->fxEscape(htmlentities(trim( trim($r[0])), ENT_QUOTES, 'UTF-8')) . "',tq_prenom='" . $GLOBALS['db']->fxEscape(htmlentities(trim($r[1]), ENT_QUOTES, 'UTF-8')) . "',tq_no='" . $r[2] . "',tq_adhesion='" . $r[3] . "',tq_naissance='" . $r[4] . "',tq_echeance='" . $r[5] . "',tq_sexe='" . $r[6] . "',tq_timeupdate=now()";
|
||||
//print_r($r);
|
||||
$newDate = date("Y-m-d", strtotime($r[7]));
|
||||
//print_rsl($r);
|
||||
|
||||
$newDate = date("Y-m-d", strtotime($r[3]));
|
||||
//echo("<br>");
|
||||
$sqlInsert = "INSERT INTO inscriptions_fnq set tq_no='" . $r[3] . "',tq_naissance='" . $newDate . "',tq_timeupdate=now()";
|
||||
$sqlInsert = "INSERT INTO inscriptions_fnq set tq_nom='" . $GLOBALS['db']->fxEscape($r[0]) . "',tq_prenom='" . $GLOBALS['db']->fxEscape($r[1] ). "',tq_sexe='" . $r[2] . "', tq_no='" . $r[4] . "',tq_naissance='" . $newDate . "',tq_timeupdate=now()";
|
||||
$qryInsert = $GLOBALS['db']->fxQuery($sqlInsert);
|
||||
|
||||
}
|
||||
@ -635,7 +639,7 @@ function fxupload_excel_fnq($mem_fichier) {
|
||||
}
|
||||
|
||||
//echo($counter);
|
||||
return $counter;
|
||||
return $counter-1;
|
||||
}
|
||||
|
||||
function fxupload_excel_triathlonv2($mem_fichier) {
|
||||
|
||||
Reference in New Issue
Block a user