Track payment method and generate sales history reports as PDF

Adds payment method tracking to sales and exports sales data to PDF using jsPDF and jspdf-autotable.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 91318273-c764-4fd4-be04-bdc12c38af32
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0715008c-7244-40f4-befc-26c014852236/bd1b8419-ee4f-46fd-822d-f546a9643613.jpg
This commit is contained in:
michaelschal committed 2025-07-09 21:25:17 +00:00
1 parent 6f065a4903
commit 0a84dec87a
8 files changed
+394 -8

No files matched your search

+29 -1
View File
@@ -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() {
</FormItem>
)}
/>
<FormField
control={form.control}
name="modePaiement"
render={({ field }) => (
<FormItem>
<FormLabel>Mode de paiement <span className="text-destructive">*</span></FormLabel>
<Select value={field.value} onValueChange={field.onChange}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Sélectionner le mode de paiement" />
</SelectTrigger>
</FormControl>
<SelectContent>
{PAYMENT_METHODS.map((method) => (
<SelectItem key={method.value} value={method.value}>
{method.label}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
@@ -473,6 +500,7 @@ export default function NewSaleForm() {
prenom: '',
dateNaissance: '',
lieuNaissance: '',
modePaiement: 'Espèce',
typeIdentite: '',
numeroIdentite: '',
autoriteDelivrance: '',
@@ -58,6 +58,7 @@ export default function SaleDetailsModal({ isOpen, sale, onClose }: SaleDetailsM
{sale.dateNaissance ? formatDate(sale.dateNaissance) : 'Non spécifiée'}
</div>
<div><span className="font-medium">Lieu de naissance:</span> {sale.lieuNaissance || 'Non spécifié'}</div>
<div><span className="font-medium">Mode de paiement:</span> {sale.modePaiement || 'Espèce'}</div>
</div>
</div>
+119 -7
View File
@@ -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) {
/>
</div>
</div>
<Button onClick={exportToCSV} variant="outline" className="touch-friendly-button w-full sm:w-auto">
<Download className="h-4 w-4 mr-2" />
<span className="hidden sm:inline">Export CSV</span>
<span className="sm:hidden">CSV</span>
</Button>
<div className="flex gap-2 w-full sm:w-auto">
<Button onClick={exportToCSV} variant="outline" className="touch-friendly-button flex-1 sm:flex-none">
<Download className="h-4 w-4 mr-2" />
<span className="hidden sm:inline">Export CSV</span>
<span className="sm:hidden">CSV</span>
</Button>
<Button onClick={exportToPDF} variant="outline" className="touch-friendly-button flex-1 sm:flex-none">
<FileText className="h-4 w-4 mr-2" />
<span className="hidden sm:inline">Export PDF</span>
<span className="sm:hidden">PDF</span>
</Button>
</div>
</div>
{/* Sales Table */}
@@ -204,6 +309,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) {
<TableHead className="responsive-caption">Client</TableHead>
<TableHead className="responsive-caption">Article</TableHead>
<TableHead className="responsive-caption">Quantité</TableHead>
<TableHead className="responsive-caption hidden lg:table-cell">Paiement</TableHead>
<TableHead className="responsive-caption hidden sm:table-cell">Gencode</TableHead>
<TableHead className="responsive-caption">Actions</TableHead>
</TableRow>
@@ -234,7 +340,12 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) {
</div>
</TableCell>
<TableCell>{sale.quantite}</TableCell>
<TableCell>{sale.gencode}</TableCell>
<TableCell className="hidden lg:table-cell">
<span className="inline-flex px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">
{sale.modePaiement || 'Espèce'}
</span>
</TableCell>
<TableCell className="hidden sm:table-cell">{sale.gencode}</TableCell>
<TableCell>
<div className="flex gap-2">
<Dialog>
@@ -274,6 +385,7 @@ export default function SalesHistory({ canDelete = false }: SalesHistoryProps) {
{selectedSale.lieuNaissance && (
<p><strong>Lieu de naissance :</strong> {selectedSale.lieuNaissance}</p>
)}
<p><strong>Mode de paiement :</strong> {selectedSale.modePaiement || 'Espèce'}</p>
</div>
<div>
<h4 className="font-medium mb-2">Pièce d'identité</h4>
+9
View File
@@ -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;
+2
View File
@@ -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;
+230
View File
@@ -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",
+3
View File
@@ -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",
+1
View File
@@ -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(),