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:
40
server/db.ts
40
server/db.ts
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}),
|
||||
}),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user