diff --git a/client/src/components/NewSaleForm.tsx b/client/src/components/NewSaleForm.tsx index 7b66f1a..d25ffc6 100644 --- a/client/src/components/NewSaleForm.tsx +++ b/client/src/components/NewSaleForm.tsx @@ -11,7 +11,7 @@ import { useToast } from '@/hooks/use-toast'; import { useAuth } from '@/hooks/useAuth'; import { useStoreContext } from '@/hooks/useStoreContext'; import { apiRequest } from '@/lib/queryClient'; -import { validateRequiredFields, validateEAN13, ARTICLE_CATEGORY_MAPPING, IDENTITY_TYPES } from '@/lib/validation'; +import { validateRequiredFields, validateEAN13, ARTICLE_CATEGORY_MAPPING, IDENTITY_TYPES, PAYMENT_METHODS } from '@/lib/validation'; import { Package, User, Users, Save, X } from 'lucide-react'; interface FormData { @@ -25,6 +25,7 @@ interface FormData { prenom: string; dateNaissance: string; lieuNaissance: string; + modePaiement: string; typeIdentite: string; numeroIdentite: string; autoriteDelivrance: string; @@ -50,6 +51,7 @@ export default function NewSaleForm() { prenom: '', dateNaissance: '', lieuNaissance: '', + modePaiement: 'Espèce', typeIdentite: '', numeroIdentite: '', autoriteDelivrance: '', @@ -92,6 +94,7 @@ export default function NewSaleForm() { prenom: '', dateNaissance: '', lieuNaissance: '', + modePaiement: 'Espèce', typeIdentite: '', numeroIdentite: '', autoriteDelivrance: '', @@ -374,6 +377,30 @@ export default function NewSaleForm() { )} /> + ( + + Mode de paiement * + + + + )} + /> @@ -473,6 +500,7 @@ export default function NewSaleForm() { prenom: '', dateNaissance: '', lieuNaissance: '', + modePaiement: 'Espèce', typeIdentite: '', numeroIdentite: '', autoriteDelivrance: '', diff --git a/client/src/components/SaleDetailsModal.tsx b/client/src/components/SaleDetailsModal.tsx index a587d80..8cbb2c0 100644 --- a/client/src/components/SaleDetailsModal.tsx +++ b/client/src/components/SaleDetailsModal.tsx @@ -58,6 +58,7 @@ export default function SaleDetailsModal({ isOpen, sale, onClose }: SaleDetailsM {sale.dateNaissance ? formatDate(sale.dateNaissance) : 'Non spécifiée'}
Lieu de naissance: {sale.lieuNaissance || 'Non spécifié'}
+
Mode de paiement: {sale.modePaiement || 'Espèce'}
diff --git a/client/src/components/SalesHistory.tsx b/client/src/components/SalesHistory.tsx index 8bbeabe..0dc93b6 100644 --- a/client/src/components/SalesHistory.tsx +++ b/client/src/components/SalesHistory.tsx @@ -11,7 +11,7 @@ import { useStoreContext } from '@/hooks/useStoreContext'; import { useAuth } from '@/hooks/useAuth'; import { apiRequest } from '@/lib/queryClient'; import type { Sale } from '@shared/schema'; -import { History, Download, Trash2, Eye, Filter } from 'lucide-react'; +import { History, Download, Trash2, Eye, Filter, FileText } from 'lucide-react'; interface SalesHistoryProps { canDelete?: boolean; @@ -75,6 +75,102 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { deleteSaleMutation.mutate(sale.id); }; + const exportToPDF = async () => { + if (sales.length === 0) { + toast({ + title: "Aucune donnée", + description: "Aucune vente à exporter", + variant: "destructive", + }); + return; + } + + const { default: jsPDF } = await import('jspdf'); + await import('jspdf-autotable'); + + const doc = new jsPDF() as any; + + // Configuration du document + doc.setFont('helvetica'); + + // Titre du document + doc.setFontSize(16); + doc.text('Historique des Ventes de Feux d\'Artifice', 20, 20); + + // Informations générales + doc.setFontSize(10); + doc.text(`Date d'export: ${new Date().toLocaleDateString('fr-FR')}`, 20, 30); + doc.text(`Nombre de ventes: ${sales.length}`, 20, 35); + + if (startDate || endDate) { + let periodText = 'Période: '; + if (startDate) periodText += `du ${new Date(startDate).toLocaleDateString('fr-FR')} `; + if (endDate) periodText += `au ${new Date(endDate).toLocaleDateString('fr-FR')}`; + doc.text(periodText, 20, 40); + } + + // Données du tableau + const tableData = sales.map(sale => [ + new Date(sale.timestamp!).toLocaleDateString('fr-FR'), + sale.vendeur, + sale.typeArticle, + sale.categorie, + sale.quantite.toString(), + sale.nom + ' ' + sale.prenom, + sale.modePaiement || 'Espèce', + sale.typeIdentite, + sale.numeroIdentite + ]); + + // Configuration du tableau + doc.autoTable({ + head: [['Date', 'Vendeur', 'Article', 'Cat.', 'Qté', 'Client', 'Paiement', 'ID Type', 'N° ID']], + body: tableData, + startY: startDate || endDate ? 50 : 45, + styles: { + fontSize: 8, + cellPadding: 2, + }, + headStyles: { + fillColor: [59, 130, 246], + textColor: 255, + fontSize: 9, + }, + alternateRowStyles: { + fillColor: [248, 250, 252], + }, + columnStyles: { + 0: { cellWidth: 18 }, // Date + 1: { cellWidth: 25 }, // Vendeur + 2: { cellWidth: 35 }, // Article + 3: { cellWidth: 12 }, // Catégorie + 4: { cellWidth: 12 }, // Quantité + 5: { cellWidth: 30 }, // Client + 6: { cellWidth: 20 }, // Paiement + 7: { cellWidth: 15 }, // ID Type + 8: { cellWidth: 25 }, // N° ID + }, + margin: { left: 10, right: 10 }, + }); + + // Pied de page + const pageCount = doc.internal.getNumberOfPages(); + for (let i = 1; i <= pageCount; i++) { + doc.setPage(i); + doc.setFontSize(8); + doc.text(`Page ${i} sur ${pageCount}`, doc.internal.pageSize.width - 30, doc.internal.pageSize.height - 10); + doc.text('RegisFlow - Registre des ventes de feux d\'artifice', 20, doc.internal.pageSize.height - 10); + } + + // Téléchargement + doc.save(`historique_ventes_${new Date().toISOString().split('T')[0]}.pdf`); + + toast({ + title: "Export PDF réussi", + description: `${sales.length} ventes exportées en PDF`, + }); + }; + const exportToCSV = () => { if (sales.length === 0) { toast({ @@ -97,6 +193,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { 'Prénom client', 'Date de naissance', 'Lieu de naissance', + 'Mode de paiement', 'Type identité', 'Numéro identité', 'Autorité délivrance', @@ -115,6 +212,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { sale.prenom, sale.dateNaissance, sale.lieuNaissance || '', + sale.modePaiement || 'Espèce', sale.typeIdentite, sale.numeroIdentite, sale.autoriteDelivrance, @@ -178,11 +276,18 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { /> - +
+ + +
{/* Sales Table */} @@ -204,6 +309,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { Client Article Quantité + Paiement Gencode Actions @@ -234,7 +340,12 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { {sale.quantite} - {sale.gencode} + + + {sale.modePaiement || 'Espèce'} + + + {sale.gencode}
@@ -274,6 +385,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) { {selectedSale.lieuNaissance && (

Lieu de naissance : {selectedSale.lieuNaissance}

)} +

Mode de paiement : {selectedSale.modePaiement || 'Espèce'}

Pièce d'identité

diff --git a/client/src/lib/validation.ts b/client/src/lib/validation.ts index 47041d5..d8f835b 100644 --- a/client/src/lib/validation.ts +++ b/client/src/lib/validation.ts @@ -23,6 +23,7 @@ export function validateRequiredFields(formData: any): string[] { { key: 'nom', label: 'Nom' }, { key: 'prenom', label: 'Prénom' }, { key: 'dateNaissance', label: 'Date de naissance' }, + { key: 'modePaiement', label: 'Mode de paiement' }, { key: 'typeIdentite', label: 'Type de pièce d\'identité' }, { key: 'numeroIdentite', label: 'Numéro de pièce d\'identité' }, { key: 'autoriteDelivrance', label: 'Autorité de délivrance' }, @@ -60,3 +61,11 @@ export const IDENTITY_TYPES = [ { value: "Passeport", label: "Passeport" }, { value: "Permis de conduire", label: "Permis de conduire" } ] as const; + +export const PAYMENT_METHODS = [ + { value: "Carte Bancaire", label: "Carte Bancaire" }, + { value: "Espèce", label: "Espèce" }, + { value: "Chèque", label: "Chèque" }, + { value: "Carte Cadeau", label: "Carte Cadeau" }, + { value: "Autre", label: "Autre" } +] as const; diff --git a/client/src/types/sale.ts b/client/src/types/sale.ts index ae3e546..7d98d48 100644 --- a/client/src/types/sale.ts +++ b/client/src/types/sale.ts @@ -17,6 +17,7 @@ export interface Sale { prenom: string; dateNaissance: string; lieuNaissance?: string; + modePaiement: string; // Identité typeIdentite: string; @@ -40,6 +41,7 @@ export interface FormData { prenom: string; dateNaissance: string; lieuNaissance: string; + modePaiement: string; typeIdentite: string; numeroIdentite: string; autoriteDelivrance: string; diff --git a/package-lock.json b/package-lock.json index fd03292..aefb965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "@radix-ui/react-tooltip": "^1.2.0", "@tanstack/react-query": "^5.60.5", "@types/bcryptjs": "^2.4.6", + "@types/jspdf": "^1.3.3", "@types/memoizee": "^0.4.12", "@types/node-cron": "^3.0.11", "bcryptjs": "^3.0.2", @@ -56,6 +57,8 @@ "express-session": "^1.18.1", "framer-motion": "^11.13.1", "input-otp": "^1.4.2", + "jspdf": "^3.0.1", + "jspdf-autotable": "^5.0.2", "lucide-react": "^0.453.0", "memoizee": "^0.4.17", "memorystore": "^1.6.7", @@ -3478,6 +3481,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jspdf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/jspdf/-/jspdf-1.3.3.tgz", + "integrity": "sha512-DqwyAKpVuv+7DniCp2Deq1xGvfdnKSNgl9Agun2w6dFvR5UKamiv4VfYUgcypd8S9ojUyARFIlZqBrYrBMQlew==", + "license": "MIT" + }, "node_modules/@types/memoizee": { "version": "0.4.12", "resolved": "https://registry.npmjs.org/@types/memoizee/-/memoizee-0.4.12.tgz", @@ -3564,6 +3573,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", @@ -3615,6 +3631,13 @@ "@types/send": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -3725,6 +3748,18 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.20", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", @@ -3769,6 +3804,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/bcryptjs": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", @@ -3883,6 +3928,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3962,6 +4019,33 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvg": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz", + "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "optional": true + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -4114,6 +4198,18 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/core-js": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.44.0.tgz", + "integrity": "sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4128,6 +4224,16 @@ "node": ">= 8" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -4383,6 +4489,16 @@ "csstype": "^3.0.2" } }, + "node_modules/dompurify": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", + "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/drizzle-kit": { "version": "0.30.4", "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.30.4.tgz", @@ -5383,6 +5499,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -5684,6 +5806,20 @@ "node": ">= 0.4" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -5888,6 +6024,33 @@ "node": ">=6" } }, + "node_modules/jspdf": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.1.tgz", + "integrity": "sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.7", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.8.1" + }, + "optionalDependencies": { + "canvg": "^3.0.11", + "core-js": "^3.6.0", + "dompurify": "^3.2.4", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf-autotable": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.2.tgz", + "integrity": "sha512-YNKeB7qmx3pxOLcNeoqAv3qTS7KuvVwkFe5AduCawpop3NOkBUtqDToxNc225MlNecxT4kP2Zy3z/y/yvGdXUQ==", + "license": "MIT", + "peerDependencies": { + "jspdf": "^2 || ^3" + } + }, "node_modules/lightningcss": { "version": "1.29.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", @@ -6669,6 +6832,13 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT", + "optional": true + }, "node_modules/pg": { "version": "8.13.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", @@ -7135,6 +7305,16 @@ ], "license": "MIT" }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -7453,6 +7633,16 @@ "node": ">=0.10.0" } }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, "node_modules/rollup": { "version": "4.24.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.4.tgz", @@ -7735,6 +7925,16 @@ "node": ">= 10.x" } }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -7874,6 +8074,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/tailwind-merge": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", @@ -7936,6 +8146,16 @@ "node": ">=6" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -8641,6 +8861,16 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 243dd3e..c838d26 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@radix-ui/react-tooltip": "^1.2.0", "@tanstack/react-query": "^5.60.5", "@types/bcryptjs": "^2.4.6", + "@types/jspdf": "^1.3.3", "@types/memoizee": "^0.4.12", "@types/node-cron": "^3.0.11", "bcryptjs": "^3.0.2", @@ -58,6 +59,8 @@ "express-session": "^1.18.1", "framer-motion": "^11.13.1", "input-otp": "^1.4.2", + "jspdf": "^3.0.1", + "jspdf-autotable": "^5.0.2", "lucide-react": "^0.453.0", "memoizee": "^0.4.17", "memorystore": "^1.6.7", diff --git a/shared/schema.ts b/shared/schema.ts index ecb7d7d..3776586 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -73,6 +73,7 @@ export const sales = pgTable("sales", { prenom: varchar("prenom", { length: 255 }).notNull(), dateNaissance: varchar("date_naissance", { length: 10 }).notNull(), lieuNaissance: varchar("lieu_naissance", { length: 255 }), + modePaiement: varchar("mode_paiement", { length: 50 }).notNull().default("Espèce"), // Identité typeIdentite: varchar("type_identite", { length: 50 }).notNull(),