Checkpoint: Ajout du filtre destinataire dans la liste des factures (dropdown + recherche textuelle), graphique "Top 10 destinataires" et liste détaillée dans le dashboard, filtre destinataire dans les paramètres SFTP (sftpRecipientFilter) avec application lors de l'export

This commit is contained in:
Manus
2026-04-12 05:20:55 -04:00
parent 604426523d
commit edf7cc704d
10 changed files with 1707 additions and 40 deletions

View File

@@ -283,7 +283,9 @@ export async function getInvoiceStats(userId: number) {
lastActivity: null,
weeklyData: [],
topSuppliers: [],
suppliersList: []
suppliersList: [],
topRecipients: [],
recipientsList: []
};
const allInvoices = await getInvoicesByUserId(userId);
@@ -352,7 +354,37 @@ export async function getInvoiceStats(userId: number) {
amount: data.amount
}))
.sort((a, b) => b.count - a.count);
// Calculate top recipients
const recipientMap = new Map<string, { count: number; amount: number }>();
completed.forEach(inv => {
const recipient = (inv as any).recipientName;
if (!recipient) return;
const current = recipientMap.get(recipient) || { count: 0, amount: 0 };
recipientMap.set(recipient, {
count: current.count + 1,
amount: current.amount + (Number(inv.totalAmount) || 0)
});
});
const topRecipients = Array.from(recipientMap.entries())
.map(([name, data]) => ({
name,
count: data.count,
amount: data.amount,
percentage: completed.length > 0 ? (data.count / completed.length * 100) : 0
}))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
const recipientsList = Array.from(recipientMap.entries())
.map(([name, data]) => ({
name,
count: data.count,
amount: data.amount
}))
.sort((a, b) => b.count - a.count);
return {
total: allInvoices.length,
completed: completed.length,
@@ -363,7 +395,9 @@ export async function getInvoiceStats(userId: number) {
lastActivity,
weeklyData,
topSuppliers,
suppliersList
suppliersList,
topRecipients,
recipientsList
};
}

View File

@@ -463,6 +463,7 @@ export const appRouter = router({
totalAmountKeywords: z.string().optional(),
subscriptionKeywords: z.string().optional(),
recipientKeywords: z.string().optional(),
sftpRecipientFilter: z.string().optional(),
sftpHost: z.string().optional(),
sftpPort: z.number().optional(),
sftpUsername: z.string().optional(),
@@ -750,9 +751,14 @@ export const appRouter = router({
if (!config) {
throw new TRPCError({ code: "BAD_REQUEST", message: "SFTP not configured" });
}
// Load user settings to check recipient filter
const userSettings = await getUserSettings(ctx.user.id);
const recipientFilter = (userSettings as any)?.sftpRecipientFilter?.trim() || "";
let successCount = 0;
let errorCount = 0;
let filteredCount = 0;
for (const invoiceId of input.invoiceIds) {
try {
@@ -761,6 +767,15 @@ export const appRouter = router({
errorCount++;
continue;
}
// Apply recipient filter if configured
if (recipientFilter) {
const invoiceRecipient = ((invoice as any).recipientName || "").toLowerCase();
if (!invoiceRecipient.includes(recipientFilter.toLowerCase())) {
filteredCount++;
continue;
}
}
await exportInvoiceToSftp(
config,
@@ -782,7 +797,7 @@ export const appRouter = router({
}
}
return { successCount, errorCount };
return { successCount, errorCount, filteredCount };
}),
}),