Checkpoint: Ajout colonne "Source import" (Email / Dossier / Fichier) dans l'historique des imports : schéma DB migré, backend mis à jour (routers.ts, emailImportService.ts, folderImportService.ts), frontend History.tsx avec badges colorés dans le tableau et le dialog de détails.
This commit is contained in:
@@ -23,6 +23,9 @@ import {
|
|||||||
RotateCcw,
|
RotateCcw,
|
||||||
Package,
|
Package,
|
||||||
X,
|
X,
|
||||||
|
Upload,
|
||||||
|
FolderOpen,
|
||||||
|
Mail,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -307,6 +310,7 @@ export default function History() {
|
|||||||
<TableRow className="bg-gray-50">
|
<TableRow className="bg-gray-50">
|
||||||
<TableHead className="font-semibold">Fichier importé</TableHead>
|
<TableHead className="font-semibold">Fichier importé</TableHead>
|
||||||
<TableHead className="font-semibold">Date d'import</TableHead>
|
<TableHead className="font-semibold">Date d'import</TableHead>
|
||||||
|
<TableHead className="font-semibold text-center">Source</TableHead>
|
||||||
<TableHead className="font-semibold text-center">Détectées</TableHead>
|
<TableHead className="font-semibold text-center">Détectées</TableHead>
|
||||||
<TableHead className="font-semibold text-center">Importées</TableHead>
|
<TableHead className="font-semibold text-center">Importées</TableHead>
|
||||||
<TableHead className="font-semibold text-center">Doublons</TableHead>
|
<TableHead className="font-semibold text-center">Doublons</TableHead>
|
||||||
@@ -326,6 +330,24 @@ export default function History() {
|
|||||||
<TableCell className="text-sm text-gray-600">
|
<TableCell className="text-sm text-gray-600">
|
||||||
{new Date(log.importedAt).toLocaleString("fr-FR")}
|
{new Date(log.importedAt).toLocaleString("fr-FR")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="text-center">
|
||||||
|
{log.importSource === "email" ? (
|
||||||
|
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-700 border border-blue-200">
|
||||||
|
<Mail className="h-3 w-3" />
|
||||||
|
Email
|
||||||
|
</span>
|
||||||
|
) : log.importSource === "folder" ? (
|
||||||
|
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-700 border border-purple-200">
|
||||||
|
<FolderOpen className="h-3 w-3" />
|
||||||
|
Dossier
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-700 border border-gray-200">
|
||||||
|
<Upload className="h-3 w-3" />
|
||||||
|
Fichier
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="text-center">
|
<TableCell className="text-center">
|
||||||
<Badge variant="outline" className="font-mono">
|
<Badge variant="outline" className="font-mono">
|
||||||
{log.totalInvoicesDetected}
|
{log.totalInvoicesDetected}
|
||||||
@@ -408,6 +430,18 @@ export default function History() {
|
|||||||
<p className="text-xs text-gray-500 font-medium mb-1">Date d'import</p>
|
<p className="text-xs text-gray-500 font-medium mb-1">Date d'import</p>
|
||||||
<p className="text-sm font-semibold">{new Date(selectedLog.importedAt).toLocaleString("fr-FR")}</p>
|
<p className="text-sm font-semibold">{new Date(selectedLog.importedAt).toLocaleString("fr-FR")}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="bg-gray-50 rounded-lg p-3">
|
||||||
|
<p className="text-xs text-gray-500 font-medium mb-1">Source import</p>
|
||||||
|
<p className="text-sm font-semibold">
|
||||||
|
{selectedLog.importSource === "email" ? (
|
||||||
|
<span className="inline-flex items-center gap-1 text-blue-700"><Mail className="h-4 w-4" /> Email</span>
|
||||||
|
) : selectedLog.importSource === "folder" ? (
|
||||||
|
<span className="inline-flex items-center gap-1 text-purple-700"><FolderOpen className="h-4 w-4" /> Dossier</span>
|
||||||
|
) : (
|
||||||
|
<span className="inline-flex items-center gap-1 text-gray-700"><Upload className="h-4 w-4" /> Fichier</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Statistiques */}
|
{/* Statistiques */}
|
||||||
|
|||||||
1
drizzle/0032_volatile_jocasta.sql
Normal file
1
drizzle/0032_volatile_jocasta.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `importLogs` ADD `importSource` enum('file','folder','email') DEFAULT 'file' NOT NULL;
|
||||||
2155
drizzle/meta/0032_snapshot.json
Normal file
2155
drizzle/meta/0032_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -225,6 +225,13 @@
|
|||||||
"when": 1781021650065,
|
"when": 1781021650065,
|
||||||
"tag": "0031_mean_squadron_supreme",
|
"tag": "0031_mean_squadron_supreme",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 32,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1781690960721,
|
||||||
|
"tag": "0032_volatile_jocasta",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -223,6 +223,8 @@ export const importLogs = mysqlTable("importLogs", {
|
|||||||
duplicateDetails: text("duplicateDetails"), // JSON array of duplicate invoice info
|
duplicateDetails: text("duplicateDetails"), // JSON array of duplicate invoice info
|
||||||
errorDetails: text("errorDetails"), // JSON array of error messages
|
errorDetails: text("errorDetails"), // JSON array of error messages
|
||||||
warningMessage: text("warningMessage"), // Warning message (e.g. quota exhausted)
|
warningMessage: text("warningMessage"), // Warning message (e.g. quota exhausted)
|
||||||
|
/** Source du mode d'import : 'file' = upload manuel, 'folder' = dossier automatique, 'email' = import par email */
|
||||||
|
importSource: mysqlEnum("importSource", ["file", "folder", "email"]).default("file").notNull(),
|
||||||
importedAt: timestamp("importedAt").defaultNow().notNull(),
|
importedAt: timestamp("importedAt").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ async function processEmailAttachment(
|
|||||||
duplicateDetails: duplicateDetails.length > 0 ? JSON.stringify(duplicateDetails) : null,
|
duplicateDetails: duplicateDetails.length > 0 ? JSON.stringify(duplicateDetails) : null,
|
||||||
errorDetails: errorDetails.length > 0 ? JSON.stringify(errorDetails) : null,
|
errorDetails: errorDetails.length > 0 ? JSON.stringify(errorDetails) : null,
|
||||||
warningMessage,
|
warningMessage,
|
||||||
|
importSource: "email",
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`[EmailImport] Successfully processed attachment: ${fileName}`);
|
console.log(`[EmailImport] Successfully processed attachment: ${fileName}`);
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ async function processFolderFile(
|
|||||||
errors: errorsCount,
|
errors: errorsCount,
|
||||||
duplicateDetails: duplicateDetails.length > 0 ? JSON.stringify(duplicateDetails) : null,
|
duplicateDetails: duplicateDetails.length > 0 ? JSON.stringify(duplicateDetails) : null,
|
||||||
errorDetails: errorDetails.length > 0 ? JSON.stringify(errorDetails) : null,
|
errorDetails: errorDetails.length > 0 ? JSON.stringify(errorDetails) : null,
|
||||||
|
importSource: "folder",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Move file to processed folder
|
// Move file to processed folder
|
||||||
|
|||||||
@@ -370,6 +370,7 @@ export const appRouter = router({
|
|||||||
errors: errorsCount,
|
errors: errorsCount,
|
||||||
duplicateDetails: JSON.stringify(duplicateDetails),
|
duplicateDetails: JSON.stringify(duplicateDetails),
|
||||||
errorDetails: JSON.stringify(errorDetails),
|
errorDetails: JSON.stringify(errorDetails),
|
||||||
|
importSource: "file",
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
8
todo.md
8
todo.md
@@ -667,3 +667,11 @@
|
|||||||
- [x] Job cron WebDev : vérification périodique selon fréquence configurée (setInterval en mémoire)
|
- [x] Job cron WebDev : vérification périodique selon fréquence configurée (setInterval en mémoire)
|
||||||
- [x] Frontend VentilationFreePro.tsx : wrapper Tabs (onglet 1 = import manuel, onglet 2 = paramétrage)
|
- [x] Frontend VentilationFreePro.tsx : wrapper Tabs (onglet 1 = import manuel, onglet 2 = paramétrage)
|
||||||
- [x] Onglet Paramétrage : formulaire credentials FreePro web, fréquence, date antériorité, bouton "Forcer récupération", statut dernière récupération
|
- [x] Onglet Paramétrage : formulaire credentials FreePro web, fréquence, date antériorité, bouton "Forcer récupération", statut dernière récupération
|
||||||
|
|
||||||
|
## Colonne Source import dans l'historique des imports
|
||||||
|
- [x] Ajouter colonne importSource (file/folder/email) dans la table importLogs (schéma + migration)
|
||||||
|
- [x] Enregistrer importSource="file" lors d'un import manuel (routers.ts)
|
||||||
|
- [x] Enregistrer importSource="email" lors d'un import par email (emailImportService.ts)
|
||||||
|
- [x] Enregistrer importSource="folder" lors d'un import par dossier (folderImportService.ts)
|
||||||
|
- [x] Afficher la colonne "Source" avec badge coloré dans le tableau History.tsx (Email=bleu, Dossier=violet, Fichier=gris)
|
||||||
|
- [x] Afficher la source dans le dialog de détails de l'import
|
||||||
|
|||||||
Reference in New Issue
Block a user