78 Commits

Author SHA1 Message Date
f6398c5035 MSIN-4378 2026-05-27 10:49:07 -04:00
025e145f6f Merge branch 'dev' of http://git.progiweb.ca/stephan/ms1inscription-v5 into dev 2026-05-27 10:48:18 -04:00
d006d75e53 ajout switch qrcode MSIN-4376 2026-05-27 10:46:01 -04:00
f83bc634a3 Clic sur un œil MSIN-4370 2026-05-27 10:08:44 -04:00
b6f0b85140 trie 2026-05-26 10:36:35 -04:00
517ff7dff6 Enhance bib assignment logic in batch processing functions to support team modes and prevent duplicates. Add detailed documentation for clarity. 2026-05-26 10:11:11 -04:00
9690f1884c Refactor batch processing functions to include epr_id in summary calculations and improve bib assignment logic 2026-05-26 09:45:29 -04:00
35b5a2a605 ajout switch qrcode MSIN-4376 2026-05-25 15:59:00 -04:00
27e1ce326c ajout switch qrcode MSIN-4376 2026-05-25 15:57:50 -04:00
ed1b5b5bd2 ajout switch qrcode MSIN-4376 2026-05-25 15:49:37 -04:00
f97ee2485a ajout switch qrcode MSIN-4376 2026-05-25 15:42:04 -04:00
8cfd6f2e35 ajout switch qrcode MSIN-4376 2026-05-25 15:38:16 -04:00
4cdd814945 ajout switch qrcode MSIN-4376 2026-05-25 15:35:26 -04:00
dab41e4857 ajout switch qrcode MSIN-4376 2026-05-25 15:34:33 -04:00
a762f5e599 ajout switch qrcode MSIN-4376 2026-05-25 15:20:46 -04:00
9d0e14b74b fin MSIN-4375 2026-05-21 08:52:44 -04:00
bd0da2651b fin MSIN-4375 2026-05-20 17:58:33 -04:00
889ceddf79 test MSIN-4375 2026-05-20 17:56:59 -04:00
bba116e7b6 test MSIN-4375 2026-05-20 17:56:35 -04:00
525ddba26f test MSIN-4375 2026-05-20 17:54:01 -04:00
5d35f38985 test MSIN-4375 2026-05-20 17:53:32 -04:00
b4864a2278 test MSIN-4375 2026-05-20 17:49:43 -04:00
a0d879502a test MSIN-4375 2026-05-20 17:42:06 -04:00
b2ed26a0aa test MSIN-4375 2026-05-20 17:39:22 -04:00
7a1685e7fa test MSIN-4375 2026-05-20 17:36:52 -04:00
f7b1a18365 test MSIN-4375 2026-05-20 17:36:01 -04:00
181b3f7d1c test MSIN-4375 2026-05-20 17:35:46 -04:00
13d6f0752a test MSIN-4375 2026-05-20 17:35:13 -04:00
98109fa0ab test MSIN-4375 2026-05-20 17:26:28 -04:00
0293ce9099 test MSIN-4375 2026-05-20 15:44:49 -04:00
36dc2f6ab0 test MSIN-4375 2026-05-20 15:44:24 -04:00
2efb46fc59 test MSIN-4375 2026-05-20 15:43:12 -04:00
ac21e4aa81 correction suite a la mep 2026-05-20 15:42:01 -04:00
509619520d enlever lancien MSIN-4370 2026-05-16 16:18:15 -04:00
de7e5ebe7f ajout undossard equipe meme participent MSIN-4370 2026-05-16 14:51:54 -04:00
891fed7c66 ajout undossard equipe meme participent MSIN-4370 2026-05-16 12:12:11 -04:00
f7f38fa752 ajout undossard equipe meme participent MSIN-4370 2026-05-16 12:09:55 -04:00
7b87f18d1a ajout undossard equipe meme participent MSIN-4370 2026-05-16 12:06:26 -04:00
4bd33db912 ajout undossard equipe meme participent MSIN-4370 2026-05-16 12:04:33 -04:00
41ecfd0756 ajout undossard equipe meme participent MSIN-4370 2026-05-16 12:01:31 -04:00
afc71f0d58 ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:57:10 -04:00
a5d85d28fb ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:55:07 -04:00
f55852a14f ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:54:19 -04:00
3eff5b3c3f ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:48:24 -04:00
5c35dd3c1b ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:46:26 -04:00
1f5cbcc8ba ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:42:46 -04:00
175d7e11db ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:39:43 -04:00
95204ed0f5 ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:16:50 -04:00
bb62c4c8b6 ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:10:53 -04:00
30bdcd1423 ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:08:09 -04:00
734f9a899d ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:05:07 -04:00
688f864c95 ajout undossard equipe meme participent MSIN-4370 2026-05-16 11:01:32 -04:00
57ffc59524 correction MSIN-4370 2026-05-16 10:40:38 -04:00
714b0e11ed correction MSIN-4370 2026-05-16 10:27:40 -04:00
b3ebb337c4 correction MSIN-4370 2026-05-16 10:26:35 -04:00
cc897bcaaa correction MSIN-4370 2026-05-16 10:23:34 -04:00
722488006d correction MSIN-4370 2026-05-16 10:21:16 -04:00
182083b6ce correction MSIN-4370 2026-05-16 10:08:15 -04:00
0dae4463ca correction MSIN-4370 2026-05-16 10:01:08 -04:00
0cf57c81fd correction MSIN-4370 2026-05-16 09:58:24 -04:00
95e4e7bb1a Merge remote-tracking branch 'gitea/dev' into dev
# Conflicts:
#	php/inc_settings.php
2026-05-16 09:57:31 -04:00
b9f1b7d550 correction MSIN-4370 2026-05-16 09:57:11 -04:00
3b5a82b01c correction MSIN-4370 2026-05-16 09:54:01 -04:00
623895be87 correction MSIN-4370 2026-05-16 09:49:26 -04:00
911fbc788c correction MSIN-4370 2026-05-16 09:47:10 -04:00
62a6f4b7f6 Add runtime folders to gitignore 2026-05-16 09:43:22 -04:00
6d5dc43a5a Add runtime folders to gitignore 2026-05-16 09:39:09 -04:00
93e198372d Add runtime folders to gitignore 2026-05-16 09:36:40 -04:00
4d5836b0ad Add runtime folders to gitignore 2026-05-16 09:26:06 -04:00
fb2525dfa4 Add runtime folders to gitignore 2026-05-13 18:18:41 -04:00
db13175202 Add runtime folders to gitignore 2026-05-13 18:01:59 -04:00
1d850d035b Add runtime folders to gitignore 2026-05-13 17:56:46 -04:00
96f78ebcb0 Add runtime folders to gitignore 2026-05-13 17:43:18 -04:00
5957c72884 Add runtime folders to gitignore 2026-05-13 17:01:54 -04:00
16cda56e02 Add runtime folders to gitignore 2026-05-13 16:38:06 -04:00
5fa2bc3db5 Add runtime folders to gitignore 2026-05-13 16:16:10 -04:00
f90347c5ba Add runtime folders to gitignore 2026-05-13 16:05:01 -04:00
9b36733035 Add runtime folders to gitignore 2026-05-13 13:54:05 -04:00
20 changed files with 583 additions and 188 deletions

45
.gitignore vendored
View File

@ -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
View 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"
}
]
}

View File

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

View File

@ -713,7 +713,8 @@ require_once("inc_header.php");
break;
case 'compte_inc_tableau_dossards':
$blnBoutonRetour = false;
include("inc_tableau_dossards.php");
// include("inc_tableau_dossards.php");
// assigmation v2 MSIN-3821
include("inc_tableau_dossards_v2.php");
break;
case 'compte_inc_tableau_epreuves':

View File

@ -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;
@ -1144,10 +1144,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;

View File

@ -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
View File

@ -0,0 +1,3 @@
<?php
echo shell_exec('/home/devinscription/deploy/deploy_dev.sh 2>&1');

View File

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

View File

@ -2039,7 +2039,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 = '';
@ -2332,6 +2337,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 +2382,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;

View File

@ -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
View 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>

View File

@ -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
// }
}
?>

View File

@ -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>';
}

View File

@ -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 dassignation</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>
@ -2693,7 +2699,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 +2709,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>
@ -2787,7 +2790,10 @@ if ($teamMode <= 0) {
<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
@ -2961,11 +2967,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);
@ -3238,11 +3247,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 +3286,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 +3350,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 +3372,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);
}
@ -3480,127 +3509,333 @@ 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 = [];
$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 (empty($participants) || empty($tabRanges)) {
return $assignments;
foreach ($rows as $r) {
$usedBib[(int)$r['no_bib']] = true;
}
return $usedBib;
}
/**
* 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;
$epr_id = intval($epr_id);
$teamMode = (int)$teamMode;
// =====================
// MODE SIMULATION → cache en mémoire
// MODE EXECUTE → on ne fait PAS confiance au cache
// =====================
$usedBib = [];
foreach ($tabRanges as $range) {
$start = (int)$range['start'];
$end = (int)$range['end'];
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);
foreach ($rows as $r) {
$usedBib[(int)$r['no_bib']] = true;
}
}
// =====================
// BOUCLE PRINCIPALE
// =====================
foreach ($participants as $p) {
$par_id = (int)$p['par_id'];
$foundBib = null;
// =====================
// CHERCHER BIB LIBRE
// =====================
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 +3911,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;
}

View File

@ -7,7 +7,7 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.39');
define('_VERSION_CODE', '4.72.54');
define('_DATE_CODE', '2026-03-09');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');

View File

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

View File

@ -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;
}
/*

View File

@ -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'];

View File

@ -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']);

View File

@ -624,10 +624,11 @@ function fxupload_excel_fnq($mem_fichier) {
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);
print_r($r);
$newDate = date("Y-m-d", strtotime($r[7]));
//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='" . $r[1] . "',tq_prenom='" . $r[2] . "',tq_sexe='" . $r[3] . "', tq_no='" . $r[3] . "',tq_naissance='" . $newDate . "',tq_timeupdate=now()";
$qryInsert = $GLOBALS['db']->fxQuery($sqlInsert);
}