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>();
|
const formationIdMap = new Map<string, number>();
|
||||||
|
|
||||||
// Importer les formations
|
// Importer les formations
|
||||||
|
console.log(`[Import] Début import de ${formations.length} formations`);
|
||||||
for (const formation of formations) {
|
for (const formation of formations) {
|
||||||
try {
|
try {
|
||||||
|
console.log(`[Import] Création formation: ${formation.nom}`);
|
||||||
const result = await db.insert(formationsTable).values({
|
const result = await db.insert(formationsTable).values({
|
||||||
nom: formation.nom,
|
nom: formation.nom,
|
||||||
description: formation.description,
|
description: formation.description,
|
||||||
publicCible: formation.publicCible,
|
|
||||||
lienUnique: generateUniqueLien(),
|
lienUnique: generateUniqueLien(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const formationId = Number(result.insertId);
|
const formationId = Number(result.insertId);
|
||||||
formationIdMap.set(formation.nom.toLowerCase(), formationId);
|
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++;
|
formationsCreated++;
|
||||||
} catch (error: any) {
|
} 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}`);
|
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
|
// Importer les séquences
|
||||||
|
console.log(`[Import] Début import de ${sequences.length} séquences`);
|
||||||
for (const sequence of sequences) {
|
for (const sequence of sequences) {
|
||||||
try {
|
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) {
|
if (!formationId) {
|
||||||
errors.push(`Formation "${sequence.formationNom}" non trouvée pour la séquence "${sequence.nom}"`);
|
errors.push(`Formation "${sequence.formationNom}" non trouvée pour la séquence "${sequence.nom}"`);
|
||||||
continue;
|
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] Vérifier le schéma de la table formations
|
||||||
- [x] Corriger le nom de colonne dans importExcel.ts (lienInscription → lienUnique)
|
- [x] Corriger le nom de colonne dans importExcel.ts (lienInscription → lienUnique)
|
||||||
- [x] Tester l'import après correction
|
- [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