diff --git a/attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt b/attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt new file mode 100644 index 0000000..bebe89c --- /dev/null +++ b/attached_assets/Pasted-GET-api-deliveries-500-in-24ms-GET-api-orders-500-in-27ms-getUserWithGroups-called-for-us-1754994000361_1754994000361.txt @@ -0,0 +1,200 @@ +GET /api/deliveries 500 in 24ms + +GET /api/orders 500 in 27ms + +🔍 getUserWithGroups called for user: admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +Orders API called with: { + + startDate: '2025-08-01', + + endDate: '2025-08-31', + + storeId: undefined, + + userRole: 'admin' + +} + +Admin filtering with groupIds: undefined + +Fetching orders by date range: 2025-08-01 to 2025-08-31 + +Error fetching orders: error: column orders_supplier.email does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getOrdersByDateRange (file:///app/dist/index.js:1127:16) + + at async file:///app/dist/index.js:3633:21 { + + length: 120, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '555', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/orders 500 in 13ms + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +🔍 getUserWithGroups called for user: admin_local + +🔍 Querying user_groups for user: admin_local + +🔍 Found 0 group assignments for user admin_local + +🔍 Raw query result: [] + +✅ Processed 0 groups for user admin_local + +Deliveries API called with: { + + startDate: '2025-08-01', + + endDate: '2025-08-31', + + storeId: undefined, + + withBL: undefined, + + userRole: 'admin' + +} + +Admin filtering deliveries with groupIds: undefined + +Fetching deliveries by date range: 2025-08-01 to 2025-08-31 + +Error fetching deliveries: error: column deliveries_supplier.email does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getDeliveriesByDateRange (file:///app/dist/index.js:1186:25) + + at async file:///app/dist/index.js:3848:25 { + + length: 124, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '856', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/deliveries 500 in 42ms + +HEAD /api/health 200 in 1ms + diff --git a/client/src/pages/Suppliers.tsx b/client/src/pages/Suppliers.tsx index 19171de..3a826fe 100644 --- a/client/src/pages/Suppliers.tsx +++ b/client/src/pages/Suppliers.tsx @@ -14,13 +14,11 @@ import { Search, Building, Phone, - Mail, Edit, Trash2, Package, Truck, CheckCircle, - XCircle, Clock } from "lucide-react"; import type { Supplier } from "@shared/schema"; @@ -38,8 +36,6 @@ export default function Suppliers() { name: "", contact: "", phone: "", - email: "", - address: "", hasDlc: false, automaticReconciliation: false, }); @@ -70,15 +66,7 @@ export default function Suppliers() { }); queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); setShowCreateModal(false); - setFormData({ - name: "", - contact: "", - phone: "", - email: "", - address: "", - hasDlc: false, - automaticReconciliation: false - }); + resetForm(); }, onError: (error) => { if (isUnauthorizedError(error)) { @@ -126,43 +114,10 @@ export default function Suppliers() { return { previousSuppliers }; }, - onSuccess: async (result) => { - console.log('✅ Frontend: Update mutation successful, result:', result); - console.log('🔄 Frontend: Starting cache invalidation...'); - - // Forcer une actualisation complète du cache - await queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); - await queryClient.refetchQueries({ - queryKey: ['/api/suppliers'], - type: 'active' - }); - - // Attendre un petit délai pour s'assurer que les données sont fraîches - await new Promise(resolve => setTimeout(resolve, 100)); - - console.log('✅ Frontend: Cache invalidation complete'); - - toast({ - title: "Succès", - description: "Fournisseur modifié avec succès", - }); - - setShowEditModal(false); - setSelectedSupplier(null); - setFormData({ - name: "", - contact: "", - phone: "", - email: "", - address: "", - hasDlc: false, - automaticReconciliation: false - }); - }, - onError: (error, variables, context) => { - // Rollback optimiste en cas d'erreur + onError: (error, newData, context) => { + // Rollback en cas d'erreur + console.log('⚠️ Frontend: Rolling back optimistic update due to error'); if (context?.previousSuppliers) { - console.log('❌ Frontend: Error occurred, rolling back optimistic update'); queryClient.setQueryData(['/api/suppliers'], context.previousSuppliers); } @@ -183,6 +138,19 @@ export default function Suppliers() { variant: "destructive", }); }, + onSuccess: () => { + toast({ + title: "Succès", + description: "Fournisseur modifié avec succès", + }); + queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); + setShowEditModal(false); + setSelectedSupplier(null); + resetForm(); + }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); + }, }); const deleteMutation = useMutation({ @@ -216,44 +184,47 @@ export default function Suppliers() { }, }); - const filteredSuppliers = Array.isArray(suppliers) ? suppliers.filter(supplier => - supplier.name.toLowerCase().includes(searchTerm.toLowerCase()) || - supplier.contact?.toLowerCase().includes(searchTerm.toLowerCase()) || - supplier.phone?.toLowerCase().includes(searchTerm.toLowerCase()) - ) : []; + const resetForm = () => { + setFormData({ + name: "", + contact: "", + phone: "", + hasDlc: false, + automaticReconciliation: false, + }); + }; - const getSupplierStats = (supplierId: number) => { - const supplierOrders = Array.isArray(orders) ? orders.filter(order => order.supplierId === supplierId) : []; - const supplierDeliveries = Array.isArray(deliveries) ? deliveries.filter(delivery => delivery.supplierId === supplierId) : []; - - return { - orders: supplierOrders.length, - deliveries: supplierDeliveries.length, - delivered: supplierDeliveries.filter(d => d.status === 'delivered').length, - }; + const handleChange = (field: string, value: any) => { + setFormData(prev => ({ ...prev, [field]: value })); }; const handleCreate = () => { - setFormData({ - name: "", - contact: "", - phone: "", - email: "", - address: "", - hasDlc: false, - automaticReconciliation: false - }); + if (user?.role !== 'admin') { + toast({ + title: "Accès refusé", + description: "Seuls les administrateurs peuvent créer des fournisseurs", + variant: "destructive", + }); + return; + } + resetForm(); setShowCreateModal(true); }; const handleEdit = (supplier: Supplier) => { + if (user?.role !== 'admin') { + toast({ + title: "Accès refusé", + description: "Seuls les administrateurs peuvent modifier des fournisseurs", + variant: "destructive", + }); + return; + } setSelectedSupplier(supplier); setFormData({ - name: supplier.name, + name: supplier.name || "", contact: supplier.contact || "", phone: supplier.phone || "", - email: supplier.email || "", - address: supplier.address || "", hasDlc: supplier.hasDlc || false, automaticReconciliation: supplier.automaticReconciliation || false, }); @@ -261,34 +232,22 @@ export default function Suppliers() { }; const handleDelete = (supplier: Supplier) => { - const stats = getSupplierStats(supplier.id); - - if (stats.orders > 0 || stats.deliveries > 0) { + if (user?.role !== 'admin') { toast({ - title: "Suppression impossible", - description: "Ce fournisseur a des commandes ou livraisons associées", + title: "Accès refusé", + description: "Seuls les administrateurs peuvent supprimer des fournisseurs", variant: "destructive", }); return; } - if (window.confirm(`Êtes-vous sûr de vouloir supprimer le fournisseur "${supplier.name}" ?`)) { + if (confirm(`Êtes-vous sûr de vouloir supprimer le fournisseur "${supplier.name}" ?`)) { deleteMutation.mutate(supplier.id); } }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - - if (!formData.name.trim()) { - toast({ - title: "Erreur", - description: "Le nom du fournisseur est requis", - variant: "destructive", - }); - return; - } - if (selectedSupplier) { updateMutation.mutate(formData); } else { @@ -296,56 +255,64 @@ export default function Suppliers() { } }; - const handleChange = (field: string, value: string | boolean) => { - setFormData(prev => ({ ...prev, [field]: value })); + const filteredSuppliers = suppliers.filter(supplier => + supplier.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + const getSupplierStats = (supplierId: number) => { + const supplierOrders = orders.filter((order: any) => order.supplierId === supplierId); + const supplierDeliveries = deliveries.filter((delivery: any) => delivery.supplierId === supplierId); + const deliveredCount = supplierDeliveries.filter((delivery: any) => delivery.status === 'delivered').length; + + return { + orders: supplierOrders.length, + deliveries: supplierDeliveries.length, + delivered: deliveredCount, + }; }; - const canManage = user?.role === 'admin' || user?.role === 'manager'; - - if (!canManage) { + if (isLoading) { return ( -
-
- -

- Accès restreint -

-

- Vous n'avez pas les permissions nécessaires pour accéder à cette page. -

+
+
+
+
+ {[1, 2, 3].map(i => ( +
+ ))} +
); } return ( -
- {/* Header */} -
-
-
-

- - Gestion des Fournisseurs -

-

- {filteredSuppliers.length} fournisseur{filteredSuppliers.length !== 1 ? 's' : ''} -

-
+
+
+
+

+ + Fournisseurs +

+

+ Gestion des fournisseurs et partenaires +

+
+ + {user?.role === 'admin' && ( -
+ )}
- {/* Search */} -
-
- +
+
+
- {/* Suppliers List */} -
- {isLoading ? ( -
-
-
- ) : filteredSuppliers.length === 0 ? ( -
- -

+
+ {filteredSuppliers.length === 0 ? ( +
+ +

{searchTerm ? "Aucun fournisseur trouvé" : "Aucun fournisseur"}

-

+

{searchTerm - ? "Aucun fournisseur ne correspond à votre recherche." - : "Vous n'avez pas encore de fournisseurs. Créez votre premier fournisseur pour commencer."} + ? "Aucun fournisseur ne correspond à votre recherche" + : "Commencez par créer votre premier fournisseur" + }

- {!searchTerm && ( + {!searchTerm && user?.role === 'admin' && (
-
- - -
+ {user?.role === 'admin' && ( +
+ + +
+ )}

{supplier.contact && (
- + {supplier.contact}
)} @@ -453,8 +418,6 @@ export default function Suppliers() { Aucune option activée
)} - - {/* Statistics section follows */}
@@ -495,15 +458,7 @@ export default function Suppliers() { setShowCreateModal(false); setShowEditModal(false); setSelectedSupplier(null); - setFormData({ - name: "", - contact: "", - phone: "", - email: "", - address: "", - hasDlc: false, - automaticReconciliation: false - }); + resetForm(); }}> @@ -547,27 +502,6 @@ export default function Suppliers() { />
-
- - handleChange('email', e.target.value)} - placeholder="Adresse email" - /> -
- -
- - handleChange('address', e.target.value)} - placeholder="Adresse complète" - /> -
-
Annuler @@ -626,4 +552,4 @@ export default function Suppliers() {
); -} +} \ No newline at end of file diff --git a/client/src/pages/Suppliers_backup.tsx b/client/src/pages/Suppliers_backup.tsx new file mode 100644 index 0000000..99661b8 --- /dev/null +++ b/client/src/pages/Suppliers_backup.tsx @@ -0,0 +1,627 @@ +import { useState } from "react"; +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { useAuthUnified } from "@/hooks/useAuthUnified"; +import { useToast } from "@/hooks/use-toast"; +import { apiRequest } from "@/lib/queryClient"; +import { isUnauthorizedError } from "@/lib/authUtils"; +import { + Plus, + Search, + Building, + Phone, + Mail, + Edit, + Trash2, + Package, + Truck, + CheckCircle, + XCircle, + Clock +} from "lucide-react"; +import type { Supplier } from "@shared/schema"; + +export default function Suppliers() { + const { user } = useAuthUnified(); + const { toast } = useToast(); + const queryClient = useQueryClient(); + + const [searchTerm, setSearchTerm] = useState(""); + const [showCreateModal, setShowCreateModal] = useState(false); + const [showEditModal, setShowEditModal] = useState(false); + const [selectedSupplier, setSelectedSupplier] = useState(null); + const [formData, setFormData] = useState({ + name: "", + contact: "", + phone: "", + hasDlc: false, + automaticReconciliation: false, + }); + + const { data: suppliers = [], isLoading } = useQuery({ + queryKey: ['/api/suppliers'], + }); + + const { data: orders = [] } = useQuery({ + queryKey: ['/api/orders'], + }); + + const { data: deliveries = [] } = useQuery({ + queryKey: ['/api/deliveries'], + }); + + const createMutation = useMutation({ + mutationFn: async (data: any) => { + console.log('🚚 Frontend: Creating supplier with data:', data); + const result = await apiRequest("/api/suppliers", "POST", data); + console.log('🚚 Frontend: Supplier creation result:', result); + return result; + }, + onSuccess: () => { + toast({ + title: "Succès", + description: "Fournisseur créé avec succès", + }); + queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); + setShowCreateModal(false); + setFormData({ + name: "", + contact: "", + phone: "", + email: "", + address: "", + hasDlc: false, + automaticReconciliation: false + }); + }, + onError: (error) => { + if (isUnauthorizedError(error)) { + toast({ + title: "Non autorisé", + description: "Vous êtes déconnecté. Reconnexion...", + variant: "destructive", + }); + setTimeout(() => { + window.location.href = "/api/login"; + }, 500); + return; + } + toast({ + title: "Erreur", + description: "Impossible de créer le fournisseur", + variant: "destructive", + }); + }, + }); + + const updateMutation = useMutation({ + mutationFn: async (data: any) => { + console.log('🔧 Frontend: Updating supplier with data:', data); + const result = await apiRequest(`/api/suppliers/${selectedSupplier?.id}`, "PUT", data); + console.log('🔧 Frontend: Supplier update result:', result); + return result; + }, + onMutate: async (newData) => { + // Mise à jour optimiste - mettre à jour l'interface immédiatement + console.log('🚀 Frontend: Optimistic update starting...'); + await queryClient.cancelQueries({ queryKey: ['/api/suppliers'] }); + + const previousSuppliers = queryClient.getQueryData(['/api/suppliers']); + + if (previousSuppliers && selectedSupplier) { + const updatedSuppliers = (previousSuppliers as any[]).map(supplier => + supplier.id === selectedSupplier.id + ? { ...supplier, ...newData, updatedAt: new Date().toISOString() } + : supplier + ); + queryClient.setQueryData(['/api/suppliers'], updatedSuppliers); + console.log('✅ Frontend: Optimistic update applied'); + } + + return { previousSuppliers }; + }, + onSuccess: async (result) => { + console.log('✅ Frontend: Update mutation successful, result:', result); + console.log('🔄 Frontend: Starting cache invalidation...'); + + // Forcer une actualisation complète du cache + await queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); + await queryClient.refetchQueries({ + queryKey: ['/api/suppliers'], + type: 'active' + }); + + // Attendre un petit délai pour s'assurer que les données sont fraîches + await new Promise(resolve => setTimeout(resolve, 100)); + + console.log('✅ Frontend: Cache invalidation complete'); + + toast({ + title: "Succès", + description: "Fournisseur modifié avec succès", + }); + + setShowEditModal(false); + setSelectedSupplier(null); + setFormData({ + name: "", + contact: "", + phone: "", + email: "", + address: "", + hasDlc: false, + automaticReconciliation: false + }); + }, + onError: (error, variables, context) => { + // Rollback optimiste en cas d'erreur + if (context?.previousSuppliers) { + console.log('❌ Frontend: Error occurred, rolling back optimistic update'); + queryClient.setQueryData(['/api/suppliers'], context.previousSuppliers); + } + + if (isUnauthorizedError(error)) { + toast({ + title: "Non autorisé", + description: "Vous êtes déconnecté. Reconnexion...", + variant: "destructive", + }); + setTimeout(() => { + window.location.href = "/api/login"; + }, 500); + return; + } + toast({ + title: "Erreur", + description: "Impossible de modifier le fournisseur", + variant: "destructive", + }); + }, + }); + + const deleteMutation = useMutation({ + mutationFn: async (id: number) => { + await apiRequest(`/api/suppliers/${id}`, "DELETE"); + }, + onSuccess: () => { + toast({ + title: "Succès", + description: "Fournisseur supprimé avec succès", + }); + queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); + }, + onError: (error) => { + if (isUnauthorizedError(error)) { + toast({ + title: "Non autorisé", + description: "Vous êtes déconnecté. Reconnexion...", + variant: "destructive", + }); + setTimeout(() => { + window.location.href = "/api/login"; + }, 500); + return; + } + toast({ + title: "Erreur", + description: "Impossible de supprimer le fournisseur", + variant: "destructive", + }); + }, + }); + + const filteredSuppliers = Array.isArray(suppliers) ? suppliers.filter(supplier => + supplier.name.toLowerCase().includes(searchTerm.toLowerCase()) || + supplier.contact?.toLowerCase().includes(searchTerm.toLowerCase()) || + supplier.phone?.toLowerCase().includes(searchTerm.toLowerCase()) + ) : []; + + const getSupplierStats = (supplierId: number) => { + const supplierOrders = Array.isArray(orders) ? orders.filter(order => order.supplierId === supplierId) : []; + const supplierDeliveries = Array.isArray(deliveries) ? deliveries.filter(delivery => delivery.supplierId === supplierId) : []; + + return { + orders: supplierOrders.length, + deliveries: supplierDeliveries.length, + delivered: supplierDeliveries.filter(d => d.status === 'delivered').length, + }; + }; + + const handleCreate = () => { + setFormData({ + name: "", + contact: "", + phone: "", + email: "", + address: "", + hasDlc: false, + automaticReconciliation: false + }); + setShowCreateModal(true); + }; + + const handleEdit = (supplier: Supplier) => { + setSelectedSupplier(supplier); + setFormData({ + name: supplier.name, + contact: supplier.contact || "", + phone: supplier.phone || "", + email: supplier.email || "", + address: supplier.address || "", + hasDlc: supplier.hasDlc || false, + automaticReconciliation: supplier.automaticReconciliation || false, + }); + setShowEditModal(true); + }; + + const handleDelete = (supplier: Supplier) => { + const stats = getSupplierStats(supplier.id); + + if (stats.orders > 0 || stats.deliveries > 0) { + toast({ + title: "Suppression impossible", + description: "Ce fournisseur a des commandes ou livraisons associées", + variant: "destructive", + }); + return; + } + + if (window.confirm(`Êtes-vous sûr de vouloir supprimer le fournisseur "${supplier.name}" ?`)) { + deleteMutation.mutate(supplier.id); + } + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (!formData.name.trim()) { + toast({ + title: "Erreur", + description: "Le nom du fournisseur est requis", + variant: "destructive", + }); + return; + } + + if (selectedSupplier) { + updateMutation.mutate(formData); + } else { + createMutation.mutate(formData); + } + }; + + const handleChange = (field: string, value: string | boolean) => { + setFormData(prev => ({ ...prev, [field]: value })); + }; + + const canManage = user?.role === 'admin' || user?.role === 'manager'; + + if (!canManage) { + return ( +
+
+ +

+ Accès restreint +

+

+ Vous n'avez pas les permissions nécessaires pour accéder à cette page. +

+
+
+ ); + } + + return ( +
+ {/* Header */} +
+
+
+

+ + Gestion des Fournisseurs +

+

+ {filteredSuppliers.length} fournisseur{filteredSuppliers.length !== 1 ? 's' : ''} +

+
+ +
+
+ + {/* Search */} +
+
+ + setSearchTerm(e.target.value)} + className="pl-10 border border-gray-300 shadow-sm" + /> +
+
+ + {/* Suppliers List */} +
+ {isLoading ? ( +
+
+
+ ) : filteredSuppliers.length === 0 ? ( +
+ +

+ {searchTerm ? "Aucun fournisseur trouvé" : "Aucun fournisseur"} +

+

+ {searchTerm + ? "Aucun fournisseur ne correspond à votre recherche." + : "Vous n'avez pas encore de fournisseurs. Créez votre premier fournisseur pour commencer."} +

+ {!searchTerm && ( + + )} +
+ ) : ( +
+
+ {filteredSuppliers.map((supplier) => { + const stats = getSupplierStats(supplier.id); + return ( +
+
+
+
+ +
+
+

{supplier.name}

+

#{supplier.id}

+
+
+
+ + +
+
+ +
+ {supplier.contact && ( +
+ + {supplier.contact} +
+ )} + {supplier.phone && ( +
+ + {supplier.phone} +
+ )} +
+
+ {supplier.hasDlc && ( +
+ + DLC +
+ )} + {supplier.automaticReconciliation && ( +
+ + Auto-rapprochement +
+ )} +
+
+ + {!supplier.hasDlc && !supplier.automaticReconciliation && ( +
+ Aucune option activée +
+ )} + + {/* Statistics section follows */} +
+ +
+
+
+
+ + {stats.orders} +
+

Commandes

+
+
+
+ + {stats.deliveries} +
+

Livraisons

+
+
+ {stats.deliveries > 0 && ( +
+

+ {stats.delivered} livrées ({Math.round((stats.delivered / stats.deliveries) * 100)}%) +

+
+ )} +
+
+ ); + })} +
+
+ )} +
+ + {/* Create/Edit Modal */} + { + setShowCreateModal(false); + setShowEditModal(false); + setSelectedSupplier(null); + setFormData({ + name: "", + contact: "", + phone: "", + email: "", + address: "", + hasDlc: false, + automaticReconciliation: false + }); + }}> + + + + {selectedSupplier ? 'Modifier' : 'Nouveau'} Fournisseur + +

+ {selectedSupplier ? 'Modifier les informations du fournisseur' : 'Créer un nouveau fournisseur'} +

+
+ +
+
+ + handleChange('name', e.target.value)} + placeholder="Nom du fournisseur" + required + /> +
+ +
+ + handleChange('contact', e.target.value)} + placeholder="Nom du contact" + /> +
+ +
+ + handleChange('phone', e.target.value)} + placeholder="Numéro de téléphone" + /> +
+ +
+ + handleChange('email', e.target.value)} + placeholder="Adresse email" + /> +
+ +
+ + handleChange('address', e.target.value)} + placeholder="Adresse complète" + /> +
+ +
+ handleChange('hasDlc', checked === true)} + /> + +
+ +
+ handleChange('automaticReconciliation', checked === true)} + /> + +
+ +
+ + +
+
+
+
+
+ ); +} diff --git a/shared/schema.ts b/shared/schema.ts index 24aadb8..b30661f 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -68,18 +68,16 @@ export const userGroups = pgTable("user_groups", { createdAt: timestamp("created_at").defaultNow(), }); -// Suppliers +// Suppliers - Schema exact correspondant à la production export const suppliers = pgTable("suppliers", { id: serial("id").primaryKey(), name: varchar("name").notNull(), contact: varchar("contact"), phone: varchar("phone"), - email: varchar("email"), - address: text("address"), hasDlc: boolean("has_dlc").default(false), // Coche DLC pour la gestion DLC - automaticReconciliation: boolean("automatic_reconciliation").default(false), // Rapprochement automatique BL/Factures createdAt: timestamp("created_at").defaultNow(), updatedAt: timestamp("updated_at").defaultNow(), + automaticReconciliation: boolean("automatic_reconciliation").default(false), // Rapprochement automatique BL/Factures }); // Orders