From c09388c0aa634599859e877ba3afa272fe09cd4a Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Mon, 1 Sep 2025 11:57:55 +0000 Subject: [PATCH] Make delivery validation require a mandatory delivery note number Enforce the requirement for a delivery note number (blNumber) during delivery validation on both the delivery and calendar modules. This change updates the frontend validation schema to make blNumber a required field with a minimum length, modifies the backend logic to reject validations without a blNumber, and integrates a new modal component for handling this validation process within the Deliveries page. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 98f01874-e00c-4bbe-9d71-b0b338001848 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/98f01874-e00c-4bbe-9d71-b0b338001848/yaZkPAT --- .../modals/ValidateDeliveryModal.tsx | 12 ++-- client/src/pages/Deliveries.tsx | 67 ++++++------------- server/routes.ts | 15 +++-- 3 files changed, 34 insertions(+), 60 deletions(-) diff --git a/client/src/components/modals/ValidateDeliveryModal.tsx b/client/src/components/modals/ValidateDeliveryModal.tsx index 2966d1e..03682b9 100644 --- a/client/src/components/modals/ValidateDeliveryModal.tsx +++ b/client/src/components/modals/ValidateDeliveryModal.tsx @@ -13,7 +13,7 @@ import { isUnauthorizedError } from "@/lib/authUtils"; import { Check, X } from "lucide-react"; const validateDeliverySchema = z.object({ - blNumber: z.string().optional(), + blNumber: z.string().min(1, "Le numéro de bon de livraison est obligatoire"), blAmount: z.string().optional(), }); @@ -47,10 +47,8 @@ export default function ValidateDeliveryModal({ mutationFn: async (data: ValidateDeliveryForm) => { const payload: any = {}; - // Ajouter blNumber seulement s'il est fourni - if (data.blNumber && data.blNumber.trim() !== '') { - payload.blNumber = data.blNumber.trim(); - } + // Le blNumber est maintenant obligatoire + payload.blNumber = data.blNumber.trim(); if (data.blAmount && data.blAmount.trim() !== '') { payload.blAmount = parseFloat(data.blAmount); @@ -137,10 +135,10 @@ export default function ValidateDeliveryModal({ name="blNumber" render={({ field }) => ( - N° Bon de Livraison + N° Bon de Livraison * diff --git a/client/src/pages/Deliveries.tsx b/client/src/pages/Deliveries.tsx index 84f3af9..8b75b98 100644 --- a/client/src/pages/Deliveries.tsx +++ b/client/src/pages/Deliveries.tsx @@ -29,6 +29,7 @@ import { safeFormat } from "@/lib/dateUtils"; import CreateDeliveryModal from "@/components/modals/CreateDeliveryModal"; import EditDeliveryModal from "@/components/modals/EditDeliveryModal"; import OrderDetailModal from "@/components/modals/OrderDetailModal"; +import ValidateDeliveryModal from "@/components/modals/ValidateDeliveryModal"; import ConfirmDeleteModal from "@/components/modals/ConfirmDeleteModal"; import type { DeliveryWithRelations } from "@shared/schema"; @@ -67,8 +68,10 @@ export default function Deliveries() { const [showEditModal, setShowEditModal] = useState(false); const [showDetailModal, setShowDetailModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); + const [showValidateModal, setShowValidateModal] = useState(false); const [selectedDelivery, setSelectedDelivery] = useState(null); const [deliveryToDelete, setDeliveryToDelete] = useState(null); + const [deliveryToValidate, setDeliveryToValidate] = useState(null); // Construire l'URL pour l'historique complet sans filtrage par date // CRITICAL FIX: Appliquer le filtrage par storeId pour TOUS les rôles, pas seulement admin @@ -107,46 +110,6 @@ export default function Deliveries() { const groups = Array.isArray(groupsData) ? groupsData : []; - const validateMutation = useMutation({ - mutationFn: async (id: number) => { - await apiRequest(`/api/deliveries/${id}/validate`, "POST"); - }, - onSuccess: () => { - toast({ - title: "Succès", - description: "Livraison validée avec succès", - }); - // Invalider tous les caches liés aux livraisons - queryClient.invalidateQueries({ queryKey: ['/api/deliveries'] }); - queryClient.invalidateQueries({ queryKey: [deliveriesUrl] }); - // Invalider tous les caches BL/Rapprochement - queryClient.invalidateQueries({ - predicate: (query) => - query.queryKey[0] === '/api/deliveries/bl' || - query.queryKey[0] === '/api/deliveries' - }); - queryClient.invalidateQueries({ queryKey: ['/api/orders'] }); - queryClient.invalidateQueries({ queryKey: ['/api/stats/monthly'] }); - }, - 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 valider la livraison", - variant: "destructive", - }); - }, - }); const deleteMutation = useMutation({ mutationFn: async (id: number) => { @@ -231,10 +194,14 @@ export default function Deliveries() { setShowEditModal(true); }; - const handleValidateDelivery = (id: number) => { - if (window.confirm("Êtes-vous sûr de vouloir valider cette livraison ?")) { - validateMutation.mutate(id); - } + const handleValidateDelivery = (delivery: DeliveryWithRelations) => { + setDeliveryToValidate(delivery); + setShowValidateModal(true); + }; + + const handleValidateModalClose = () => { + setShowValidateModal(false); + setDeliveryToValidate(null); }; const handleDeleteDelivery = (delivery: DeliveryWithRelations) => { @@ -448,9 +415,9 @@ export default function Deliveries() { @@ -513,6 +480,14 @@ export default function Deliveries() { /> )} + {showValidateModal && deliveryToValidate && ( + + )} + {/* Modal de confirmation de suppression */} { const { blNumber, blAmount } = req.body; - // BL data is optional - delivery can be validated without it - let blData: any = undefined; - if (blNumber) { - blData = { blNumber }; - if (blAmount !== undefined && blAmount !== null && blAmount !== '') { - blData.blAmount = blAmount; - } + // Le numéro de BL est maintenant obligatoire pour valider une livraison + if (!blNumber || !blNumber.trim()) { + return res.status(400).json({ message: "Le numéro de bon de livraison est obligatoire pour valider une livraison" }); + } + + let blData: any = { blNumber: blNumber.trim() }; + if (blAmount !== undefined && blAmount !== null && blAmount !== '') { + blData.blAmount = blAmount; } await storage.validateDelivery(id, blData);