Checkpoint: Correction du bug d'import Excel - Retrait de la colonne publicCible inexistante dans la table formations. Ajout de logs de débogage et amélioration de la gestion des erreurs d'import.

This commit is contained in:
Manus Sandbox
2025-11-25 14:22:36 -05:00
parent 5fde389c85
commit c4f9cb9ebc
6 changed files with 204 additions and 2 deletions

View File

@@ -0,0 +1,66 @@
{
"query": "DESCRIBE formations;",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute DESCRIBE formations;",
"rows": [
{
"Field": "id",
"Type": "int(11)",
"Null": "NO",
"Key": "PRI",
"Default": "NULL",
"Extra": "auto_increment"
},
{
"Field": "nom",
"Type": "varchar(255)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "description",
"Type": "text",
"Null": "YES",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "lienUnique",
"Type": "varchar(100)",
"Null": "NO",
"Key": "UNI",
"Default": "NULL",
"Extra": ""
},
{
"Field": "actif",
"Type": "tinyint(1)",
"Null": "NO",
"Key": "",
"Default": "1",
"Extra": ""
},
{
"Field": "createdAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": ""
},
{
"Field": "updatedAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": "DEFAULT_GENERATED on update CURRENT_TIMESTAMP"
}
],
"messages": [],
"stdout": "Field\tType\tNull\tKey\tDefault\tExtra\nid\tint(11)\tNO\tPRI\tNULL\tauto_increment\nnom\tvarchar(255)\tNO\t\tNULL\t\ndescription\ttext\tYES\t\tNULL\t\nlienUnique\tvarchar(100)\tNO\tUNI\tNULL\t\nactif\ttinyint(1)\tNO\t\t1\t\ncreatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\t\nupdatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\tDEFAULT_GENERATED on update CURRENT_TIMESTAMP\n",
"stderr": "",
"execution_time_ms": 54
}

View File

@@ -0,0 +1,66 @@
{
"query": "SHOW COLUMNS FROM formations;",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SHOW COLUMNS FROM formations;",
"rows": [
{
"Field": "id",
"Type": "int(11)",
"Null": "NO",
"Key": "PRI",
"Default": "NULL",
"Extra": "auto_increment"
},
{
"Field": "nom",
"Type": "varchar(255)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "description",
"Type": "text",
"Null": "YES",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "lienUnique",
"Type": "varchar(100)",
"Null": "NO",
"Key": "UNI",
"Default": "NULL",
"Extra": ""
},
{
"Field": "actif",
"Type": "tinyint(1)",
"Null": "NO",
"Key": "",
"Default": "1",
"Extra": ""
},
{
"Field": "createdAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": ""
},
{
"Field": "updatedAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": "DEFAULT_GENERATED on update CURRENT_TIMESTAMP"
}
],
"messages": [],
"stdout": "Field\tType\tNull\tKey\tDefault\tExtra\nid\tint(11)\tNO\tPRI\tNULL\tauto_increment\nnom\tvarchar(255)\tNO\t\tNULL\t\ndescription\ttext\tYES\t\tNULL\t\nlienUnique\tvarchar(100)\tNO\tUNI\tNULL\t\nactif\ttinyint(1)\tNO\t\t1\t\ncreatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\t\nupdatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\tDEFAULT_GENERATED on update CURRENT_TIMESTAMP\n",
"stderr": "",
"execution_time_ms": 51
}

View File

@@ -0,0 +1,8 @@
{
"query": "SELECT id, nom, description, publicCible, lienUnique, createdAt FROM formations ORDER BY createdAt DESC LIMIT 10;",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SELECT id, nom, description, publicCible, lienUnique, createdAt FROM formations ORDER BY createdAt DESC LIMIT 10;",
"returncode": 1,
"logs": [
"ERROR 1054 (42S22) at line 1: Unknown column 'publiccible' in 'field list'"
]
}

View File

@@ -192,27 +192,47 @@ export async function importToDatabase(
const formationIdMap = new Map<string, number>();
// Importer les formations
console.log(`[Import] Début import de ${formations.length} formations`);
for (const formation of formations) {
try {
console.log(`[Import] Création formation: ${formation.nom}`);
const result = await db.insert(formationsTable).values({
nom: formation.nom,
description: formation.description,
publicCible: formation.publicCible,
lienUnique: generateUniqueLien(),
});
const formationId = Number(result.insertId);
formationIdMap.set(formation.nom.toLowerCase(), formationId);
console.log(`[Import] Formation créée avec ID ${formationId}, ajoutée à la map avec clé: "${formation.nom.toLowerCase()}"`);
formationsCreated++;
} catch (error: any) {
console.error(`[Import] Erreur formation "${formation.nom}":`, error);
errors.push(`Erreur lors de la création de la formation "${formation.nom}": ${error.message}`);
}
}
console.log(`[Import] Formations créées: ${formationsCreated}, Map size: ${formationIdMap.size}`);
console.log(`[Import] Clés dans la map:`, Array.from(formationIdMap.keys()));
// Si des erreurs sont survenues lors de la création des formations, arrêter l'import
if (errors.length > 0) {
console.error(`[Import] Arrêt de l'import car ${errors.length} erreur(s) lors de la création des formations`);
return {
success: false,
formationsCreated,
sequencesCreated: 0,
errors,
warnings,
};
}
// Importer les séquences
console.log(`[Import] Début import de ${sequences.length} séquences`);
for (const sequence of sequences) {
try {
const formationId = formationIdMap.get(sequence.formationNom.toLowerCase());
const searchKey = sequence.formationNom.toLowerCase();
console.log(`[Import] Recherche formation pour séquence "${sequence.nom}" avec clé: "${searchKey}"`);
const formationId = formationIdMap.get(searchKey);
if (!formationId) {
errors.push(`Formation "${sequence.formationNom}" non trouvée pour la séquence "${sequence.nom}"`);
continue;

29
test-import.ts Normal file
View File

@@ -0,0 +1,29 @@
import { parseExcelFile, validateImportData } from './server/importExcel';
import { readFileSync } from 'fs';
const buffer = readFileSync('/home/ubuntu/upload/template_import_formations_test.xlsx');
const { formations, sequences } = parseExcelFile(buffer);
console.log('=== FORMATIONS PARSÉES ===');
console.log(`Total: ${formations.length}`);
formations.forEach((f, i) => {
console.log(`${i}: nom="${f.nom}", desc="${f.description}", public="${f.publicCible}"`);
});
console.log('\n=== SÉQUENCES PARSÉES ===');
console.log(`Total: ${sequences.length}`);
sequences.forEach((s, i) => {
console.log(`${i}: formation="${s.formationNom}", nom="${s.nom}", lieu="${s.lieu}"`);
});
console.log('\n=== VALIDATION ===');
const validation = validateImportData(formations, sequences);
console.log(`Valid: ${validation.valid}`);
if (validation.errors.length > 0) {
console.log('Erreurs:');
validation.errors.forEach(e => console.log(` - ${e}`));
}
if (validation.warnings.length > 0) {
console.log('Avertissements:');
validation.warnings.forEach(w => console.log(` - ${w}`));
}

13
todo.md
View File

@@ -664,3 +664,16 @@
- [x] Vérifier le schéma de la table formations
- [x] Corriger le nom de colonne dans importExcel.ts (lienInscription → lienUnique)
- [x] Tester l'import après correction
## Bug import Excel - Formation non trouvée après création
- [ ] Analyser le fichier Excel de test fourni
- [ ] Identifier pourquoi la formation n'est pas trouvée dans la map
- [ ] Corriger la logique d'import
- [ ] Tester avec le fichier Excel fourni
## Bug import Excel - Erreur nom de colonne publicCible
- [x] Vérifier le schéma de la table formations en base de données (publicCible n'existe pas dans formations)
- [x] Corriger le code d'import (retiré publicCible de l'insertion formations)
- [x] Tester l'import après correction