Checkpoint: Ajout de la colonne 'Export SP' dans le tableau historique de Ventilation FreePro : icône horloge grise = non exporté, icône verte = exporté (date au survol), icône rouge = erreur (message au survol). Le statut est sauvegardé en base (sharepointUploadStatus, sharepointUploadPath, sharepointUploadError, sharepointExportedAt) lors de chaque export via 'Envoyer vers SharePoint'.
This commit is contained in:
@@ -66,6 +66,10 @@ interface ImportRecord {
|
|||||||
nbLignes: number;
|
nbLignes: number;
|
||||||
totalTtc: string | null;
|
totalTtc: string | null;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
sharepointUploadStatus: 'success' | 'error' | null;
|
||||||
|
sharepointUploadPath: string | null;
|
||||||
|
sharepointUploadError: string | null;
|
||||||
|
sharepointExportedAt: Date | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Helpers ────────────────────────────────────────────────────────────────
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||||
@@ -847,6 +851,7 @@ function VentilationFreeProContent() {
|
|||||||
<TableHead className="text-right">Lignes</TableHead>
|
<TableHead className="text-right">Lignes</TableHead>
|
||||||
<TableHead className="text-right">Total TTC</TableHead>
|
<TableHead className="text-right">Total TTC</TableHead>
|
||||||
<TableHead>Importé le</TableHead>
|
<TableHead>Importé le</TableHead>
|
||||||
|
<TableHead className="text-center">Export SP</TableHead>
|
||||||
<TableHead className="text-right">Actions</TableHead>
|
<TableHead className="text-right">Actions</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
@@ -876,6 +881,29 @@ function VentilationFreeProContent() {
|
|||||||
<TableCell className="text-xs text-muted-foreground">
|
<TableCell className="text-xs text-muted-foreground">
|
||||||
{new Date(imp.createdAt).toLocaleDateString("fr-FR")}
|
{new Date(imp.createdAt).toLocaleDateString("fr-FR")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
|
||||||
|
{imp.sharepointUploadStatus === 'success' ? (
|
||||||
|
<span
|
||||||
|
title={`Exporté le ${imp.sharepointExportedAt ? new Date(imp.sharepointExportedAt).toLocaleString('fr-FR') : ''}${imp.sharepointUploadPath ? '\n' + imp.sharepointUploadPath : ''}`}
|
||||||
|
className="inline-flex items-center gap-1 text-green-600 cursor-default"
|
||||||
|
>
|
||||||
|
<CheckCircle2 className="h-4 w-4" />
|
||||||
|
<span className="text-xs hidden sm:inline">Exporté</span>
|
||||||
|
</span>
|
||||||
|
) : imp.sharepointUploadStatus === 'error' ? (
|
||||||
|
<span
|
||||||
|
title={`Erreur : ${imp.sharepointUploadError || 'Erreur inconnue'}`}
|
||||||
|
className="inline-flex items-center gap-1 text-red-500 cursor-default"
|
||||||
|
>
|
||||||
|
<XCircle className="h-4 w-4" />
|
||||||
|
<span className="text-xs hidden sm:inline">Erreur</span>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="inline-flex items-center gap-1 text-muted-foreground/40 cursor-default" title="Non exporté vers SharePoint">
|
||||||
|
<Clock className="h-4 w-4" />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="text-right">
|
<TableCell className="text-right">
|
||||||
<div className="flex items-center justify-end gap-1" onClick={(e) => e.stopPropagation()}>
|
<div className="flex items-center justify-end gap-1" onClick={(e) => e.stopPropagation()}>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
4
drizzle/0030_vengeful_warbird.sql
Normal file
4
drizzle/0030_vengeful_warbird.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `freeproImports` ADD `sharepointUploadStatus` enum('success','error');--> statement-breakpoint
|
||||||
|
ALTER TABLE `freeproImports` ADD `sharepointUploadPath` text;--> statement-breakpoint
|
||||||
|
ALTER TABLE `freeproImports` ADD `sharepointUploadError` text;--> statement-breakpoint
|
||||||
|
ALTER TABLE `freeproImports` ADD `sharepointExportedAt` timestamp;
|
||||||
2140
drizzle/meta/0030_snapshot.json
Normal file
2140
drizzle/meta/0030_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -211,6 +211,13 @@
|
|||||||
"when": 1780924653802,
|
"when": 1780924653802,
|
||||||
"tag": "0029_unknown_spot",
|
"tag": "0029_unknown_spot",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 30,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1780930222253,
|
||||||
|
"tag": "0030_vengeful_warbird",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -442,6 +442,14 @@ export const freeproImports = mysqlTable("freeproImports", {
|
|||||||
nbLignes: int("nbLignes").default(0).notNull(),
|
nbLignes: int("nbLignes").default(0).notNull(),
|
||||||
/** Total général TTC calculé */
|
/** Total général TTC calculé */
|
||||||
totalTtc: varchar("totalTtc", { length: 30 }),
|
totalTtc: varchar("totalTtc", { length: 30 }),
|
||||||
|
/** Statut de l'export SharePoint : null = jamais exporté, 'success' = exporté, 'error' = erreur */
|
||||||
|
sharepointUploadStatus: mysqlEnum("sharepointUploadStatus", ["success", "error"]),
|
||||||
|
/** URL/chemin du fichier dans SharePoint après export réussi */
|
||||||
|
sharepointUploadPath: text("sharepointUploadPath"),
|
||||||
|
/** Message d'erreur si l'export SharePoint a échoué */
|
||||||
|
sharepointUploadError: text("sharepointUploadError"),
|
||||||
|
/** Date de l'export SharePoint */
|
||||||
|
sharepointExportedAt: timestamp("sharepointExportedAt"),
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|||||||
20
server/db.ts
20
server/db.ts
@@ -1008,6 +1008,26 @@ export async function getFreeproImportWithLines(
|
|||||||
return { import: imports[0], lines };
|
return { import: imports[0], lines };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Met à jour le statut d'export SharePoint d'un import FreePro */
|
||||||
|
export async function updateFreeproSharepointStatus(
|
||||||
|
importId: number,
|
||||||
|
status: 'success' | 'error',
|
||||||
|
path?: string | null,
|
||||||
|
error?: string | null
|
||||||
|
): Promise<void> {
|
||||||
|
const db = await getDb();
|
||||||
|
if (!db) return;
|
||||||
|
await db
|
||||||
|
.update(freeproImports)
|
||||||
|
.set({
|
||||||
|
sharepointUploadStatus: status,
|
||||||
|
sharepointUploadPath: path ?? null,
|
||||||
|
sharepointUploadError: error ?? null,
|
||||||
|
sharepointExportedAt: new Date(),
|
||||||
|
})
|
||||||
|
.where(eq(freeproImports.id, importId));
|
||||||
|
}
|
||||||
|
|
||||||
/** Supprime un import FreePro et ses lignes */
|
/** Supprime un import FreePro et ses lignes */
|
||||||
export async function deleteFreeproImport(importId: number): Promise<void> {
|
export async function deleteFreeproImport(importId: number): Promise<void> {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
|
|||||||
@@ -2436,9 +2436,16 @@ export const appRouter = router({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
|
// Sauvegarder le statut d'erreur en base
|
||||||
|
const { updateFreeproSharepointStatus } = await import('./db');
|
||||||
|
await updateFreeproSharepointStatus(input.id, 'error', null, result.error || 'Erreur inconnue');
|
||||||
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: result.error || 'Erreur upload SharePoint' });
|
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: result.error || 'Erreur upload SharePoint' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sauvegarder le statut de succès en base
|
||||||
|
const { updateFreeproSharepointStatus } = await import('./db');
|
||||||
|
await updateFreeproSharepointStatus(input.id, 'success', result.webUrl || null, null);
|
||||||
|
|
||||||
return { success: true, webUrl: result.webUrl, fileName };
|
return { success: true, webUrl: result.webUrl, fileName };
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user