fix: expliciter le résultat des imports manuels

This commit is contained in:
Manus
2026-10-02 21:10:42 +00:00
parent ba4e42c7f1
commit 1617267128
3 changed files with 68 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ import {
} from "lucide-react";
import { toast } from "sonner";
import { useLocation } from "wouter";
import { parseImportResultSummary } from "@shared/importResultSummary";
interface UploadedFile {
name: string;
@@ -24,6 +25,9 @@ interface UploadedFile {
status: "pending" | "processing" | "completed" | "error";
progress?: string;
invoicesDetected?: number;
importedCount?: number;
duplicateCount?: number;
errorCount?: number;
}
export default function Upload() {
@@ -66,11 +70,15 @@ export default function Upload() {
prev.map((f) => {
if (f.sourceFileId !== sf.id) return f;
if (f.status === sf.processingStatus) return f;
const summary = parseImportResultSummary(sf.processingProgress);
return {
...f,
status: (sf.processingStatus ?? "pending") as UploadedFile["status"],
progress: sf.processingProgress ?? undefined,
invoicesDetected: sf.totalInvoicesDetected ?? undefined,
importedCount: summary?.importedCount,
duplicateCount: summary?.duplicateCount,
errorCount: summary?.errorCount,
};
})
);
@@ -165,6 +173,10 @@ export default function Upload() {
const processingCount = uploadedFiles.filter(
(f) => f.status === "processing" || f.status === "pending"
).length;
const importedInvoiceCount = uploadedFiles.reduce(
(total, file) => total + (file.importedCount ?? 0),
0,
);
return (
<DashboardLayout>
@@ -282,8 +294,11 @@ export default function Upload() {
<div>
<CardTitle>Fichiers importés</CardTitle>
<CardDescription>
{completedCount > 0 && (
<span className="text-green-600 font-medium">{completedCount} terminé(s) </span>
{completedCount > 0 && importedInvoiceCount > 0 && (
<span className="text-green-600 font-medium">{importedInvoiceCount} facture(s) créée(s) </span>
)}
{completedCount > 0 && importedInvoiceCount === 0 && (
<span className="text-amber-700 font-medium">{completedCount} terminé(s), aucune facture créée </span>
)}
{processingCount > 0 && (
<span className="text-blue-600 font-medium">{processingCount} en cours </span>
@@ -294,7 +309,7 @@ export default function Upload() {
</CardDescription>
</div>
<div className="flex gap-2">
{completedCount > 0 && (
{importedInvoiceCount > 0 && (
<Button
size="sm"
onClick={() => setLocation("/invoices")}
@@ -332,10 +347,16 @@ export default function Upload() {
{f.status === "processing" && (
<p className="text-xs text-muted-foreground">{f.progress || "Traitement en cours..."}</p>
)}
{f.status === "completed" && f.invoicesDetected !== undefined && (
{f.status === "completed" && f.importedCount !== undefined && (
f.importedCount > 0 ? (
<p className="text-xs text-green-600">
{f.invoicesDetected} facture(s) détectée(s)
{f.importedCount} facture(s) créée(s)
</p>
) : (
<p className="text-xs text-amber-700">
Aucune facture créée{f.duplicateCount ? ` : ${f.duplicateCount} doublon(s) ou facture(s) supprimée(s)` : ""}
</p>
)
)}
{f.status === "error" && (
<p className="text-xs text-red-500">{f.progress || "Erreur de traitement"}</p>

View File

@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import { parseImportResultSummary } from "@shared/importResultSummary";
describe("parseImportResultSummary", () => {
it("identifie un traitement terminé sans facture créée", () => {
expect(parseImportResultSummary("Terminé: 0 importée(s), 1 doublon(s)"))
.toEqual({ importedCount: 0, duplicateCount: 1, errorCount: 0 });
});
it("identifie une facture réellement créée", () => {
expect(parseImportResultSummary("Terminé: 1 importée(s), 0 doublon(s)"))
.toEqual({ importedCount: 1, duplicateCount: 0, errorCount: 0 });
});
it("conserve les erreurs éventuelles", () => {
expect(parseImportResultSummary("Terminé: 0 importée(s), 0 doublon(s), 1 erreur(s)"))
.toEqual({ importedCount: 0, duplicateCount: 0, errorCount: 1 });
});
it("retourne null pour un statut intermédiaire", () => {
expect(parseImportResultSummary("Extraction 1/1 factures...")).toBeNull();
});
});

View File

@@ -0,0 +1,17 @@
export type ImportResultSummary = {
importedCount: number;
duplicateCount: number;
errorCount: number;
};
/** Extrait le résultat final affiché par les services d'import. */
export function parseImportResultSummary(progress: string | null | undefined): ImportResultSummary | null {
if (!progress) return null;
const match = progress.match(/Termin[ée]\s*:\s*(\d+)\s+importée\(s\),\s*(\d+)\s+doublon\(s\)(?:,\s*(\d+)\s+erreur\(s\))?/i);
if (!match) return null;
return {
importedCount: Number(match[1]),
duplicateCount: Number(match[2]),
errorCount: Number(match[3] ?? 0),
};
}