Checkpoint: Checkpoint saved: Implémentation complète de l'import automatique par email.
Nouvelles fonctionnalités : ✅ Service d'import automatique par email (emailImportService.ts) ✅ Connexion IMAP avec support SSL/TLS ✅ Détection automatique des nouveaux emails non lus avec pièces jointes PDF ✅ Téléchargement et traitement des pièces jointes (même logique que l'upload manuel) ✅ Marquage des emails comme lus après traitement réussi ✅ Scheduler configurable (fréquence en minutes) ✅ Routes tRPC pour démarrer/arrêter/vérifier le statut du service ✅ Boutons de contrôle dans la page Paramètres de réception Fonctionnement : 1. L'utilisateur configure ses identifiants email dans "Paramètres de réception" 2. Il active l'import par email et configure la fréquence de vérification 3. Il clique sur "Démarrer le service" pour lancer la surveillance 4. Le service se connecte au serveur IMAP selon la fréquence configurée 5. Il détecte les nouveaux emails non lus avec pièces jointes PDF 6. Il télécharge chaque PDF et applique le même traitement que l'upload manuel : - Stockage local du fichier - Extraction avec Mistral AI - Détection de doublons - Création des factures en base de données - Génération des métadonnées JSON - Création du log d'import 7. Les emails traités sont marqués comme lus 8. Le service continue de tourner en arrière-plan selon la fréquence configurée Interface utilisateur : - Indicateur visuel "Service actif" avec point vert animé - Bouton "Démarrer le service" (désactivé si l'import email n'est pas activé) - Bouton "Arrêter le service" (rouge) pour stopper la surveillance - Messages toast pour confirmer le démarrage/arrêt Dépendances ajoutées : - imap : Client IMAP pour Node.js - mailparser : Parser d'emails avec support des pièces jointes - @types/imap et @types/mailparser : Types TypeScript Le service est maintenant prêt à être testé avec un vrai compte email IMAP.
This commit is contained in:
@@ -6,12 +6,15 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { toast } from "sonner";
|
||||
import { Loader2, Save, Upload, FolderOpen, Mail } from "lucide-react";
|
||||
import { Loader2, Save, Upload, FolderOpen, Mail, Play, Square } from "lucide-react";
|
||||
import DashboardLayout from "@/components/DashboardLayout";
|
||||
|
||||
export default function ImportSettings() {
|
||||
const { data: settings, isLoading } = trpc.importSettings.get.useQuery();
|
||||
const { data: serviceStatus } = trpc.emailImportService.status.useQuery();
|
||||
const updateMutation = trpc.importSettings.update.useMutation();
|
||||
const startServiceMutation = trpc.emailImportService.start.useMutation();
|
||||
const stopServiceMutation = trpc.emailImportService.stop.useMutation();
|
||||
|
||||
// Manual import
|
||||
const [manualImportEnabled, setManualImportEnabled] = useState(true);
|
||||
@@ -280,6 +283,70 @@ export default function ImportSettings() {
|
||||
Intervalle de temps entre chaque vérification des emails (minimum: 1 minute)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Service Control Buttons */}
|
||||
<div className="flex gap-2 pt-4 border-t">
|
||||
{serviceStatus?.isRunning ? (
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={async () => {
|
||||
try {
|
||||
await stopServiceMutation.mutateAsync();
|
||||
toast.success("Service arrêté", {
|
||||
description: "L'import automatique par email a été arrêté.",
|
||||
});
|
||||
} catch (error) {
|
||||
toast.error("Erreur", {
|
||||
description: "Impossible d'arrêter le service.",
|
||||
});
|
||||
}
|
||||
}}
|
||||
disabled={stopServiceMutation.isPending}
|
||||
>
|
||||
{stopServiceMutation.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Square className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Arrêter le service
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={async () => {
|
||||
try {
|
||||
const result = await startServiceMutation.mutateAsync();
|
||||
if (result.success) {
|
||||
toast.success("Service démarré", {
|
||||
description: "L'import automatique par email est maintenant actif.",
|
||||
});
|
||||
} else {
|
||||
toast.error("Erreur", {
|
||||
description: "Impossible de démarrer le service. Vérifiez la configuration.",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("Erreur", {
|
||||
description: "Impossible de démarrer le service.",
|
||||
});
|
||||
}
|
||||
}}
|
||||
disabled={!emailImportEnabled || startServiceMutation.isPending}
|
||||
>
|
||||
{startServiceMutation.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Démarrer le service
|
||||
</Button>
|
||||
)}
|
||||
{serviceStatus?.isRunning && (
|
||||
<span className="flex items-center text-sm text-green-600">
|
||||
<span className="w-2 h-2 bg-green-600 rounded-full mr-2 animate-pulse" />
|
||||
Service actif
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user