Checkpoint: La route /api/download-bap accepte maintenant un param filename et le met dans Content-Disposition (RFC 5987). Les fonctions downloadBapPdf dans InvoicesBAP.tsx et BapHistory.tsx passent le filename formaté dans l'URL.
This commit is contained in:
@@ -30,15 +30,16 @@ function downloadBapPdf(
|
|||||||
validatedAt?: Date | string | null
|
validatedAt?: Date | string | null
|
||||||
) {
|
) {
|
||||||
const fallback = pdfUrl.split('/').pop() || 'BAP.pdf';
|
const fallback = pdfUrl.split('/').pop() || 'BAP.pdf';
|
||||||
const downloadUrl = `/api/download-bap?pdfPath=${encodeURIComponent(pdfUrl)}`;
|
|
||||||
// Construire le nom de fichier : date - fournisseur - numero.pdf
|
// Construire le nom de fichier : date - fournisseur - numero.pdf
|
||||||
const datePart = validatedAt
|
const datePart = validatedAt
|
||||||
? new Date(validatedAt).toLocaleDateString('fr-CA') // format AAAA-MM-JJ
|
? new Date(validatedAt).toLocaleDateString('fr-CA') // format AAAA-MM-JJ
|
||||||
: '';
|
: '';
|
||||||
const supplierPart = (supplierName || '').replace(/[^a-zA-Z0-9à-ÿ \-]/g, '').trim();
|
const supplierPart = (supplierName || '').replace(/[^a-zA-Z0-9\u00e0-\u00ff \-]/g, '').trim();
|
||||||
const numberPart = (invoiceNumber || '').replace(/[^a-zA-Z0-9\-]/g, '').trim();
|
const numberPart = (invoiceNumber || '').replace(/[^a-zA-Z0-9\-]/g, '').trim();
|
||||||
const parts = [datePart, supplierPart, numberPart].filter(Boolean);
|
const parts = [datePart, supplierPart, numberPart].filter(Boolean);
|
||||||
const filename = parts.length > 0 ? `${parts.join(' - ')}.pdf` : fallback;
|
const filename = parts.length > 0 ? `${parts.join(' - ')}.pdf` : fallback;
|
||||||
|
// Passer le filename au serveur pour qu'il soit dans Content-Disposition
|
||||||
|
const downloadUrl = `/api/download-bap?pdfPath=${encodeURIComponent(pdfUrl)}&filename=${encodeURIComponent(filename)}`;
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = downloadUrl;
|
a.href = downloadUrl;
|
||||||
a.download = filename;
|
a.download = filename;
|
||||||
|
|||||||
@@ -43,14 +43,15 @@ function downloadBapPdf(
|
|||||||
validatedAt?: Date | string | null
|
validatedAt?: Date | string | null
|
||||||
) {
|
) {
|
||||||
const fallback = pdfUrl.split('/').pop() || 'BAP.pdf';
|
const fallback = pdfUrl.split('/').pop() || 'BAP.pdf';
|
||||||
const downloadUrl = `/api/download-bap?pdfPath=${encodeURIComponent(pdfUrl)}`;
|
|
||||||
const datePart = validatedAt
|
const datePart = validatedAt
|
||||||
? new Date(validatedAt).toLocaleDateString('fr-CA') // AAAA-MM-JJ
|
? new Date(validatedAt).toLocaleDateString('fr-CA') // AAAA-MM-JJ
|
||||||
: new Date().toLocaleDateString('fr-CA');
|
: new Date().toLocaleDateString('fr-CA');
|
||||||
const supplierPart = (supplierName || '').replace(/[^a-zA-Z0-9à-ÿ \-]/g, '').trim();
|
const supplierPart = (supplierName || '').replace(/[^a-zA-Z0-9\u00e0-\u00ff \-]/g, '').trim();
|
||||||
const numberPart = (invoiceNumber || '').replace(/[^a-zA-Z0-9\-]/g, '').trim();
|
const numberPart = (invoiceNumber || '').replace(/[^a-zA-Z0-9\-]/g, '').trim();
|
||||||
const parts = [datePart, supplierPart, numberPart].filter(Boolean);
|
const parts = [datePart, supplierPart, numberPart].filter(Boolean);
|
||||||
const filename = parts.length > 0 ? `${parts.join(' - ')}.pdf` : fallback;
|
const filename = parts.length > 0 ? `${parts.join(' - ')}.pdf` : fallback;
|
||||||
|
// Passer le filename au serveur pour qu'il soit dans Content-Disposition
|
||||||
|
const downloadUrl = `/api/download-bap?pdfPath=${encodeURIComponent(pdfUrl)}&filename=${encodeURIComponent(filename)}`;
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = downloadUrl;
|
a.href = downloadUrl;
|
||||||
a.download = filename;
|
a.download = filename;
|
||||||
|
|||||||
@@ -61,8 +61,13 @@ async function startServer() {
|
|||||||
res.status(404).json({ error: "Fichier introuvable" });
|
res.status(404).json({ error: "Fichier introuvable" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filename = path.basename(storagePath);
|
// Utiliser le nom de fichier fourni par le client (format Date - Fournisseur - N°Facture.pdf)
|
||||||
res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(filename)}"`);
|
const customFilename = req.query.filename as string | undefined;
|
||||||
|
const fallbackFilename = path.basename(storagePath);
|
||||||
|
const finalFilename = customFilename ? customFilename : fallbackFilename;
|
||||||
|
// RFC 5987 : utiliser filename* pour les caractères non-ASCII
|
||||||
|
const encodedFilename = encodeURIComponent(finalFilename);
|
||||||
|
res.setHeader("Content-Disposition", `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`);
|
||||||
res.setHeader("Content-Type", "application/pdf");
|
res.setHeader("Content-Type", "application/pdf");
|
||||||
res.sendFile(storagePath);
|
res.sendFile(storagePath);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user