diff --git a/client/src/pages/BLReconciliation.tsx b/client/src/pages/BLReconciliation.tsx index 8566a08..d9c09ee 100644 --- a/client/src/pages/BLReconciliation.tsx +++ b/client/src/pages/BLReconciliation.tsx @@ -9,7 +9,8 @@ import { useToast } from "@/hooks/use-toast"; import { apiRequest } from "@/lib/queryClient"; import { useStore } from "@/components/Layout"; import { useAuthUnified } from "@/hooks/useAuthUnified"; -import { Search, Edit, FileText, Settings, Eye, AlertTriangle, X } from "lucide-react"; +import { usePermissions } from "@shared/permissions"; +import { Search, Edit, FileText, Settings, Eye, AlertTriangle, X, Check, Trash2, Ban } from "lucide-react"; export default function BLReconciliation() { const { user } = useAuthUnified(); @@ -81,17 +82,126 @@ export default function BLReconciliation() { return supplier?.automaticReconciliation; }); - // Fonction pour dévalider un rapprochement automatique (directeurs et admins uniquement) - const handleDevalidateAutoReconciliation = async (deliveryId: number) => { - if (user?.role !== 'directeur' && user?.role !== 'admin') { + // Fonction pour valider un rapprochement (admins et directeurs) + const handleValidateReconciliation = async (deliveryId: number) => { + if (!permissions.canValidate('reconciliation')) { toast({ title: "Accès refusé", - description: "Seuls les directeurs et administrateurs peuvent dévalider les rapprochements automatiques", + description: "Vous n'avez pas les permissions pour valider les rapprochements", variant: "destructive", }); return; } + if (!window.confirm("Êtes-vous sûr de vouloir valider ce rapprochement ?")) { + return; + } + + try { + await apiRequest(`/api/deliveries/${deliveryId}`, "PUT", { + reconciled: true, + validatedAt: new Date().toISOString() + }); + + toast({ + title: "Succès", + description: "Rapprochement validé avec succès", + }); + + queryClient.invalidateQueries({ queryKey: ['/api/deliveries/bl'] }); + } catch (error) { + toast({ + title: "Erreur", + description: "Impossible de valider le rapprochement", + variant: "destructive", + }); + } + }; + + // Fonction pour dévalider un rapprochement (admins uniquement) + const handleDevalidateReconciliation = async (deliveryId: number) => { + if (user?.role !== 'admin') { + toast({ + title: "Accès refusé", + description: "Seuls les administrateurs peuvent dévalider les rapprochements", + variant: "destructive", + }); + return; + } + + if (!window.confirm("Êtes-vous sûr de vouloir dévalider ce rapprochement ?")) { + return; + } + + try { + await apiRequest(`/api/deliveries/${deliveryId}`, "PUT", { + reconciled: false, + validatedAt: null + }); + + toast({ + title: "Succès", + description: "Rapprochement dévalidé avec succès", + }); + + queryClient.invalidateQueries({ queryKey: ['/api/deliveries/bl'] }); + } catch (error) { + toast({ + title: "Erreur", + description: "Impossible de dévalider le rapprochement", + variant: "destructive", + }); + } + }; + + // Fonction pour supprimer une livraison (admins uniquement) + const handleDeleteDelivery = async (deliveryId: number) => { + if (!permissions.canDelete('reconciliation')) { + toast({ + title: "Accès refusé", + description: "Seuls les administrateurs peuvent supprimer les livraisons", + variant: "destructive", + }); + return; + } + + if (!window.confirm("Êtes-vous sûr de vouloir supprimer cette livraison ? Cette action est irréversible.")) { + return; + } + + try { + await apiRequest(`/api/deliveries/${deliveryId}`, "DELETE"); + + toast({ + title: "Succès", + description: "Livraison supprimée avec succès", + }); + + queryClient.invalidateQueries({ queryKey: ['/api/deliveries/bl'] }); + } catch (error) { + toast({ + title: "Erreur", + description: "Impossible de supprimer la livraison", + variant: "destructive", + }); + } + }; + + // Fonction pour dévalider un rapprochement automatique (admins uniquement) + const handleDevalidateAutoReconciliation = async (deliveryId: number) => { + if (user?.role !== 'admin') { + toast({ + title: "Accès refusé", + description: "Seuls les administrateurs peuvent dévalider les rapprochements automatiques", + variant: "destructive", + }); + return; + } + + if (!window.confirm("Êtes-vous sûr de vouloir dévalider ce rapprochement automatique ?")) { + return; + } + try { await apiRequest(`/api/deliveries/${deliveryId}`, "PUT", { reconciled: false, @@ -235,7 +345,12 @@ export default function BLReconciliation() { {filteredManualDeliveries.map((delivery: any) => ( - +
{delivery.supplier?.name} @@ -283,11 +398,58 @@ export default function BLReconciliation() {
+ {/* Actions selon le statut de rapprochement et les permissions */} + {!delivery.reconciled ? ( + // Livraison non rapprochée : Valider + Supprimer + <> + {permissions.canValidate('reconciliation') && ( + + )} + {permissions.canDelete('reconciliation') && ( + + )} + + ) : ( + // Livraison rapprochée : Dévalider (admin seulement) + Supprimer + <> + {user?.role === 'admin' && ( + + )} + {permissions.canDelete('reconciliation') && ( + + )} + + )} + {/* Bouton Voir les détails toujours disponible */}
@@ -309,10 +471,10 @@ export default function BLReconciliation() {

Mode rapprochement automatique

Les livraisons de fournisseurs en mode automatique sont validées automatiquement lorsqu'elles ont le statut "delivered" et un numéro de BL. - {canModify ? ( + {user?.role === 'admin' ? ( " Vous pouvez dévalider ces rapprochements si nécessaire." ) : ( - " Seuls les directeurs et administrateurs peuvent modifier ces rapprochements." + " Seuls les administrateurs peuvent dévalider ces rapprochements." )}

@@ -367,7 +529,12 @@ export default function BLReconciliation() { {filteredAutomaticDeliveries.map((delivery: any) => ( - +
@@ -422,28 +589,20 @@ export default function BLReconciliation() {
- {canModify ? ( - <> - - - - ) : ( + + {/* Dévalider automatique - admin uniquement */} + {user?.role === 'admin' && ( )}