Enhance PDF export to include full sales information and improve layout

Modify SalesHistory component to include complete sales data in PDF export using jsPDF.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e80fed01-7137-4997-b9af-dad57132d430
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0715008c-7244-40f4-befc-26c014852236/e80fed01-7137-4997-b9af-dad57132d430/lMVWh0V
This commit is contained in:
michaelschal committed 2025-07-19 11:03:35 +00:00
1 parent 933ea44342
commit a46a0c63a4
1 file changed
+102 -39
+102 -39
View File
@@ -111,7 +111,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) {
doc.setFont('helvetica'); doc.setFont('helvetica');
doc.setFontSize(16); doc.setFontSize(16);
doc.text('Historique des Ventes de Feux d\'Artifice', 20, 20); doc.text('Registre Détaillé des Ventes de Feux d\'Artifice', 20, 20);
doc.setFontSize(10); doc.setFontSize(10);
doc.text(`Généré le ${new Date().toLocaleDateString('fr-FR')} à ${new Date().toLocaleTimeString('fr-FR')}`, 20, 30); doc.text(`Généré le ${new Date().toLocaleDateString('fr-FR')} à ${new Date().toLocaleTimeString('fr-FR')}`, 20, 30);
@@ -121,53 +121,116 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) {
doc.text(period, 20, 35); doc.text(period, 20, 35);
} }
// Créer une ligne pour chaque produit de chaque vente let currentY = startDate || endDate ? 50 : 45;
const tableData: string[][] = [];
// Pour chaque vente, créer une section complète
filteredSales.forEach((sale, saleIndex) => {
// Vérifier si on a assez de place, sinon nouvelle page
if (currentY > 250) {
doc.addPage();
currentY = 20;
}
// Titre de la vente
doc.setFontSize(12);
doc.setFont('helvetica', 'bold');
doc.text(`VENTE #${sale.id} - ${new Date(sale.timestamp).toLocaleDateString('fr-FR')} ${new Date(sale.timestamp).toLocaleTimeString('fr-FR')}`, 20, currentY);
currentY += 10;
// Informations vendeur
doc.setFontSize(10);
doc.setFont('helvetica', 'normal');
doc.text(`Vendeur: ${sale.vendeur}`, 20, currentY);
currentY += 8;
// Informations client
doc.setFont('helvetica', 'bold');
doc.text('INFORMATIONS CLIENT:', 20, currentY);
currentY += 6;
doc.setFont('helvetica', 'normal');
doc.text(`Nom: ${sale.nom} ${sale.prenom}`, 25, currentY);
currentY += 5;
doc.text(`Date de naissance: ${sale.dateNaissance || 'Non spécifiée'}`, 25, currentY);
currentY += 5;
doc.text(`Lieu de naissance: ${sale.lieuNaissance || 'Non spécifié'}`, 25, currentY);
currentY += 5;
doc.text(`Mode de paiement: ${sale.modePaiement || 'Non spécifié'}`, 25, currentY);
currentY += 8;
// Informations identité
doc.setFont('helvetica', 'bold');
doc.text('PIÈCE D\'IDENTITÉ:', 20, currentY);
currentY += 6;
doc.setFont('helvetica', 'normal');
doc.text(`Type: ${sale.typeIdentite || 'Non spécifié'}`, 25, currentY);
currentY += 5;
doc.text(`Numéro: ${sale.numeroIdentite || 'Non spécifié'}`, 25, currentY);
currentY += 5;
doc.text(`Autorité de délivrance: ${sale.autoriteDelivrance || 'Non spécifiée'}`, 25, currentY);
currentY += 5;
doc.text(`Date de délivrance: ${sale.dateDelivrance || 'Non spécifiée'}`, 25, currentY);
currentY += 8;
// Produits
doc.setFont('helvetica', 'bold');
doc.text('PRODUITS VENDUS:', 20, currentY);
currentY += 6;
filteredSales.forEach(sale => {
if (sale.products && sale.products.length > 0) { if (sale.products && sale.products.length > 0) {
// Pour chaque produit, créer une ligne avec les infos de la vente sale.products.forEach((product, productIndex) => {
sale.products.forEach(product => { doc.setFont('helvetica', 'normal');
tableData.push([ doc.text(`Produit ${productIndex + 1}:`, 25, currentY);
new Date(sale.timestamp).toLocaleDateString('fr-FR'), currentY += 5;
sale.vendeur, doc.text(` • Type: ${product.typeArticle}`, 30, currentY);
`${sale.nom} ${sale.prenom}`, currentY += 4;
product.typeArticle, doc.text(` • Catégorie: ${product.categorie}`, 30, currentY);
product.categorie, currentY += 4;
product.quantite.toString(), doc.text(` • Quantité: ${product.quantite}`, 30, currentY);
sale.modePaiement, currentY += 4;
product.gencode || '' doc.text(` • Code: ${product.gencode || 'Non spécifié'}`, 30, currentY);
]); currentY += 6;
}); });
} else { } else {
// Fallback pour les ventes sans produits (anciennes données) doc.setFont('helvetica', 'normal');
tableData.push([ doc.text('Aucun produit enregistré', 25, currentY);
new Date(sale.timestamp).toLocaleDateString('fr-FR'), currentY += 6;
sale.vendeur, }
`${sale.nom} ${sale.prenom}`,
'N/A', // Photos
'N/A', if (sale.photoRecto || sale.photoVerso || sale.photoTicket) {
'0', doc.setFont('helvetica', 'bold');
sale.modePaiement, doc.text('DOCUMENTS PHOTOGRAPHIÉS:', 20, currentY);
'' currentY += 6;
]); doc.setFont('helvetica', 'normal');
if (sale.photoRecto) {
doc.text('✓ Photo recto pièce d\'identité', 25, currentY);
currentY += 5;
}
if (sale.photoVerso) {
doc.text('✓ Photo verso pièce d\'identité', 25, currentY);
currentY += 5;
}
if (sale.photoTicket) {
doc.text('✓ Photo ticket/reçu', 25, currentY);
currentY += 5;
}
currentY += 5;
}
// Ligne de séparation si pas la dernière vente
if (saleIndex < filteredSales.length - 1) {
doc.setLineWidth(0.5);
doc.line(20, currentY, 190, currentY);
currentY += 15;
} }
}); });
autoTable(doc, { doc.save(`registre-detaille-feux-artifice-${new Date().toISOString().split('T')[0]}.pdf`);
head: [['Date', 'Vendeur', 'Client', 'Article', 'Cat.', 'Qty', 'Paiement', 'Code']],
body: tableData,
startY: startDate || endDate ? 45 : 40,
styles: { fontSize: 8 },
headStyles: { fillColor: [64, 64, 64] },
margin: { top: 40, left: 20, right: 20 },
});
doc.save(`ventes-feux-artifice-${new Date().toISOString().split('T')[0]}.pdf`);
toast({ toast({
title: "Export réussi", title: "Export réussi",
description: "Le fichier PDF a été téléchargé", description: "Le registre détaillé PDF a été téléchargé",
variant: "success", variant: "success",
}); });
} catch (error) { } catch (error) {
@@ -358,7 +421,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) {
className="modern-button modern-button-secondary" className="modern-button modern-button-secondary"
> >
<FileText className="h-4 w-4" /> <FileText className="h-4 w-4" />
Export PDF Registre PDF Détaillé
</button> </button>
<button <button
onClick={exportToCSV} onClick={exportToCSV}