MSIN-4520 — Implement functions for improved handling of Excel/CSV imports, including conversion of cell values to strings and building column indices based on headers. Update import logic to ensure accurate mapping of 'no_bib' values. Increment version code to 4.73.008 to reflect changes in import header matching and data processing.
This commit is contained in:
@ -267,6 +267,86 @@ function fxImportResultatsGuessField($strHeader) {
|
||||
return $tabCandidates[0]['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4520 — cellule Excel/CSV → string (évite 1.0 / float vide).
|
||||
*/
|
||||
function fxImportResultatsCellToString($mix) {
|
||||
if ($mix === null) {
|
||||
return '';
|
||||
}
|
||||
if (is_bool($mix)) {
|
||||
return $mix ? '1' : '0';
|
||||
}
|
||||
if (is_int($mix)) {
|
||||
return (string)$mix;
|
||||
}
|
||||
if (is_float($mix)) {
|
||||
if (is_nan($mix) || is_infinite($mix)) {
|
||||
return '';
|
||||
}
|
||||
if (floor($mix) == $mix) {
|
||||
return (string)intval($mix);
|
||||
}
|
||||
$str = rtrim(rtrim(sprintf('%.12F', $mix), '0'), '.');
|
||||
return ($str === '-0') ? '0' : $str;
|
||||
}
|
||||
return trim((string)$mix);
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4520 — index colonnes : d’abord par nom d’en-tête (profil), puis index, puis filet guess.
|
||||
* Évite « Bib → Dossard » à l’écran mais no_bib vide en BD (profil réappliqué au mauvais index).
|
||||
*/
|
||||
function fxImportResultatsBuildColIndex(array $tabColumns, array $tabHeaders, array $tabSavedHeaders = array()) {
|
||||
$tabColIndex = array();
|
||||
|
||||
foreach ($tabColumns as $intIdx => $strKey) {
|
||||
$strKey = (string)$strKey;
|
||||
if ($strKey === '') {
|
||||
continue;
|
||||
}
|
||||
$strSavedH = trim((string)($tabSavedHeaders[$intIdx] ?? ''));
|
||||
if ($strSavedH === '') {
|
||||
continue;
|
||||
}
|
||||
$strSavedNorm = fxImportResultatsNormalizeHeader($strSavedH);
|
||||
foreach ($tabHeaders as $intHi => $strH) {
|
||||
if (fxImportResultatsNormalizeHeader($strH) === $strSavedNorm) {
|
||||
$tabColIndex[$strKey] = intval($intHi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tabColumns as $intIdx => $strKey) {
|
||||
$strKey = (string)$strKey;
|
||||
if ($strKey === '' || isset($tabColIndex[$strKey])) {
|
||||
continue;
|
||||
}
|
||||
$tabColIndex[$strKey] = intval($intIdx);
|
||||
}
|
||||
|
||||
// Filet dossard : en-tête « Bib » / « Dossard » même si le mapping d’index a loupé
|
||||
$intGuessBib = -1;
|
||||
foreach ($tabHeaders as $intHi => $strH) {
|
||||
if (fxImportResultatsGuessField($strH) === 'no_bib') {
|
||||
$intGuessBib = intval($intHi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($intGuessBib >= 0) {
|
||||
$intMapped = isset($tabColIndex['no_bib']) ? intval($tabColIndex['no_bib']) : -1;
|
||||
$strMappedGuess = ($intMapped >= 0)
|
||||
? fxImportResultatsGuessField((string)($tabHeaders[$intMapped] ?? ''))
|
||||
: '';
|
||||
if ($intMapped < 0 || $strMappedGuess !== 'no_bib') {
|
||||
$tabColIndex['no_bib'] = $intGuessBib;
|
||||
}
|
||||
}
|
||||
|
||||
return $tabColIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clé de partage templates entre événements du même org (pas de com_id sur evenements).
|
||||
* MSIN-4482 — stockée dans inscriptions_import_templates.com_id (legacy name = org_id).
|
||||
@ -807,8 +887,8 @@ function fxImportResultatsSheetRawToRows(array $tabRaw) {
|
||||
if (!is_array($tabRaw) || count($tabRaw) < 1) {
|
||||
return array('state' => 'error', 'message' => 'Feuille Excel vide.');
|
||||
}
|
||||
$tabHeaders = array_map(function ($v) {
|
||||
return trim((string)$v);
|
||||
$tabHeaders = array_map(function ($v) {
|
||||
return fxImportResultatsCellToString($v);
|
||||
}, $tabRaw[0]);
|
||||
while (count($tabHeaders) > 0 && end($tabHeaders) === '') {
|
||||
array_pop($tabHeaders);
|
||||
@ -836,9 +916,7 @@ function fxImportResultatsSheetRawToRows(array $tabRaw) {
|
||||
if ($blnEmpty) {
|
||||
continue;
|
||||
}
|
||||
$tabRows[] = array_map(function ($v) {
|
||||
return trim((string)$v);
|
||||
}, $tabRow);
|
||||
$tabRows[] = array_map('fxImportResultatsCellToString', $tabRow);
|
||||
}
|
||||
return array('state' => 'ok', 'headers' => $tabHeaders, 'rows' => $tabRows);
|
||||
}
|
||||
@ -961,7 +1039,7 @@ function fxImportResultatsParseExcel($strPath, array $arrOptions = array()) {
|
||||
if (!isset($tabWantNorm[$strName])) {
|
||||
continue;
|
||||
}
|
||||
$tabRaw = $objSheet->toArray(null, true, true, false);
|
||||
$tabRaw = $objSheet->toArray(null, true, false, false);
|
||||
if (!is_array($tabRaw)) {
|
||||
continue;
|
||||
}
|
||||
@ -997,7 +1075,7 @@ function fxImportResultatsParseExcel($strPath, array $arrOptions = array()) {
|
||||
} else {
|
||||
$objSheet = $objBook->getActiveSheet();
|
||||
}
|
||||
$tabRaw = $objSheet->toArray(null, true, true, false);
|
||||
$tabRaw = $objSheet->toArray(null, true, false, false);
|
||||
} catch (Exception $ex) {
|
||||
return array('state' => 'error', 'message' => 'Lecture Excel échouée : ' . $ex->getMessage());
|
||||
}
|
||||
@ -1467,7 +1545,7 @@ function fxImportResultatsFindEventImportProfile($intEveId) {
|
||||
if (!is_array($tabCheck) || empty($tabCheck[1]['ok'])) {
|
||||
return null;
|
||||
}
|
||||
$sql = "SELECT tpl_id, eve_id, com_id, tpl_name, tpl_header_sig, tpl_mapping_json, tpl_maj"
|
||||
$sql = "SELECT tpl_id, eve_id, com_id, tpl_name, tpl_header_sig, tpl_headers_json, tpl_mapping_json, tpl_maj"
|
||||
. " FROM inscriptions_import_templates"
|
||||
. " WHERE tpl_actif = 1 AND eve_id = " . $intEveId
|
||||
. " ORDER BY tpl_maj DESC LIMIT 25";
|
||||
@ -1481,6 +1559,10 @@ function fxImportResultatsFindEventImportProfile($intEveId) {
|
||||
if (!is_array($arrMap)) {
|
||||
$arrMap = array();
|
||||
}
|
||||
$tabSavedH = json_decode((string)($tab[$i]['tpl_headers_json'] ?? ''), true);
|
||||
if (is_array($tabSavedH) && empty($arrMap['column_headers'])) {
|
||||
$arrMap['column_headers'] = $tabSavedH;
|
||||
}
|
||||
$arrRow = array(
|
||||
'tpl_id' => intval($tab[$i]['tpl_id']),
|
||||
'eve_id' => intval($tab[$i]['eve_id']),
|
||||
@ -2358,16 +2440,13 @@ function fxImportResultatsCommit($intEveId, $strToken, array $arrMapping) {
|
||||
$tabPayValues = isset($arrMapping['pay_values']) && is_array($arrMapping['pay_values']) ? $arrMapping['pay_values'] : array();
|
||||
$tabProValues = isset($arrMapping['pro_values']) && is_array($arrMapping['pro_values']) ? $arrMapping['pro_values'] : array();
|
||||
$tabQuestionsMap = isset($arrMapping['questions']) && is_array($arrMapping['questions']) ? $arrMapping['questions'] : array();
|
||||
|
||||
$tabColIndex = array();
|
||||
foreach ($tabColumns as $intIdx => $strKey) {
|
||||
$strKey = (string)$strKey;
|
||||
if ($strKey === '') {
|
||||
continue;
|
||||
}
|
||||
$tabColIndex[$strKey] = intval($intIdx);
|
||||
$tabMapHeaders = array();
|
||||
if (isset($arrMapping['column_headers']) && is_array($arrMapping['column_headers'])) {
|
||||
$tabMapHeaders = $arrMapping['column_headers'];
|
||||
}
|
||||
|
||||
$tabColIndex = fxImportResultatsBuildColIndex($tabColumns, $tabHeaders, $tabMapHeaders);
|
||||
|
||||
$tabQueIds = fxImportResultatsResolveQuestionIds($intEveId, $tabHeaders, $tabQuestionsMap);
|
||||
$strNow = function_exists('fxGetDateTime') ? fxGetDateTime() : date('Y-m-d H:i:s');
|
||||
$strOrigine = MSIN_IMPORT_RESULTATS_ORIGIN;
|
||||
@ -2380,7 +2459,9 @@ function fxImportResultatsCommit($intEveId, $strToken, array $arrMapping) {
|
||||
foreach ($tabRows as $intRowNum => $tabRow) {
|
||||
$intLine = $intRowNum + 2; // +1 header Excel, +1 index 0
|
||||
$strNamePreview = fxImportResultatsRowLabel($tabRow, $tabColIndex);
|
||||
$strBibPreview = isset($tabColIndex['no_bib']) ? trim((string)($tabRow[$tabColIndex['no_bib']] ?? '')) : '';
|
||||
$strBibPreview = isset($tabColIndex['no_bib'])
|
||||
? fxImportResultatsCellToString($tabRow[$tabColIndex['no_bib']] ?? '')
|
||||
: '';
|
||||
$strSexePreview = '';
|
||||
if (isset($tabColIndex['par_sexe'])) {
|
||||
$strSexePreview = fxImportResultatsNormalizeSex(trim((string)($tabRow[$tabColIndex['par_sexe']] ?? '')));
|
||||
@ -2459,7 +2540,7 @@ function fxImportResultatsCommit($intEveId, $strToken, array $arrMapping) {
|
||||
if (!isset($tabColIndex[$strKey])) {
|
||||
continue;
|
||||
}
|
||||
$strRaw = trim((string)($tabRow[$tabColIndex[$strKey]] ?? ''));
|
||||
$strRaw = fxImportResultatsCellToString($tabRow[$tabColIndex[$strKey]] ?? '');
|
||||
if ($strKey === 'par_sexe') {
|
||||
$arrFields[$strKey] = fxImportResultatsNormalizeSex($strRaw);
|
||||
} elseif ($strKey === 'par_naissance') {
|
||||
@ -2717,6 +2798,7 @@ function fxImportResultatsCommit($intEveId, $strToken, array $arrMapping) {
|
||||
. " pec_id = " . $intPecLink . ","
|
||||
. " rol_id = 2,"
|
||||
. " no_bib = '" . fxImportResultatsDbEsc($arrFields['no_bib']) . "',"
|
||||
. " par_statut_course = 'CONF',"
|
||||
. " par_external_id = '" . fxImportResultatsDbEsc($strExt) . "',"
|
||||
. " par_origine = '" . fxImportResultatsDbEsc($strOrigine) . "'";
|
||||
if ($objDatabase->fxQuery($sqlPar) === false) {
|
||||
@ -3842,6 +3924,7 @@ function fxImportResultatsRenderEventPanel($intEveId) {
|
||||
// MSIN-4520 — figer mode onglets + pays/province dans le profil événement
|
||||
var mapping = {
|
||||
columns: columns,
|
||||
column_headers: (state.headers || []).slice(),
|
||||
epr_values: epr_values,
|
||||
pay_values: pay_values,
|
||||
pro_values: pro_values,
|
||||
@ -4032,9 +4115,26 @@ function fxImportResultatsRenderEventPanel($intEveId) {
|
||||
function applyMappingObj(mapping) {
|
||||
if (!mapping || !mapping.columns) return;
|
||||
state.appliedMapping = mapping;
|
||||
var savedHeaders = mapping.column_headers || mapping._headers || [];
|
||||
var columns = mapping.columns || [];
|
||||
$('#ms1_import_map_table tbody select.js-col-map').each(function (i) {
|
||||
if (mapping.columns[i] != null) {
|
||||
$(this).val(String(mapping.columns[i]));
|
||||
var field = '';
|
||||
var hNow = (state.headers && state.headers[i] != null) ? String(state.headers[i]) : '';
|
||||
var hNowN = hNow.toLowerCase().replace(/\s+/g, ' ').trim();
|
||||
if (savedHeaders.length && hNowN !== '') {
|
||||
for (var j = 0; j < savedHeaders.length; j++) {
|
||||
var hOld = String(savedHeaders[j] || '').toLowerCase().replace(/\s+/g, ' ').trim();
|
||||
if (hOld === hNowN && columns[j]) {
|
||||
field = String(columns[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!field && columns[i] != null) {
|
||||
field = String(columns[i]);
|
||||
}
|
||||
if (field) {
|
||||
$(this).val(field);
|
||||
}
|
||||
});
|
||||
renderEprBox();
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
* Constantes *
|
||||
*
|
||||
**************/
|
||||
define('_VERSION_CODE', '4.73.007'); // MSIN-4520 — reset import: delete par_id (pas LIMIT/affected_rows superadm)
|
||||
define('_VERSION_CODE', '4.73.008'); // MSIN-4520 — import dossard: match en-tête Bib + valeurs Excel brutes
|
||||
define('_DATE_CODE', '2026-08-14');
|
||||
//MSIN-4290
|
||||
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
|
||||
|
||||
Reference in New Issue
Block a user