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:
66
.manus/db/db-query-1764098411417.json
Normal file
66
.manus/db/db-query-1764098411417.json
Normal 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
|
||||
}
|
||||
66
.manus/db/db-query-1764098425699.json
Normal file
66
.manus/db/db-query-1764098425699.json
Normal 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
|
||||
}
|
||||
8
.manus/db/db-query-error-1764098316699.json
Normal file
8
.manus/db/db-query-error-1764098316699.json
Normal 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'"
|
||||
]
|
||||
}
|
||||
@@ -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
29
test-import.ts
Normal 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
13
todo.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user