mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-22 06:28:19 +02:00
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
This commit is contained in:
1 parent
6dca340c45
commit
c09388c0aa
3 files changed
+34
-60
No files matched your search
@@ -13,7 +13,7 @@ import { isUnauthorizedError } from "@/lib/authUtils";
|
|||||||
import { Check, X } from "lucide-react";
|
import { Check, X } from "lucide-react";
|
||||||
|
|
||||||
const validateDeliverySchema = z.object({
|
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(),
|
blAmount: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -47,10 +47,8 @@ export default function ValidateDeliveryModal({
|
|||||||
mutationFn: async (data: ValidateDeliveryForm) => {
|
mutationFn: async (data: ValidateDeliveryForm) => {
|
||||||
const payload: any = {};
|
const payload: any = {};
|
||||||
|
|
||||||
// Ajouter blNumber seulement s'il est fourni
|
// Le blNumber est maintenant obligatoire
|
||||||
if (data.blNumber && data.blNumber.trim() !== '') {
|
payload.blNumber = data.blNumber.trim();
|
||||||
payload.blNumber = data.blNumber.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.blAmount && data.blAmount.trim() !== '') {
|
if (data.blAmount && data.blAmount.trim() !== '') {
|
||||||
payload.blAmount = parseFloat(data.blAmount);
|
payload.blAmount = parseFloat(data.blAmount);
|
||||||
@@ -137,10 +135,10 @@ export default function ValidateDeliveryModal({
|
|||||||
name="blNumber"
|
name="blNumber"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>N° Bon de Livraison</FormLabel>
|
<FormLabel>N° Bon de Livraison *</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Ex: BL-2024-001 (optionnel)"
|
placeholder="Ex: BL-2024-001"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { safeFormat } from "@/lib/dateUtils";
|
|||||||
import CreateDeliveryModal from "@/components/modals/CreateDeliveryModal";
|
import CreateDeliveryModal from "@/components/modals/CreateDeliveryModal";
|
||||||
import EditDeliveryModal from "@/components/modals/EditDeliveryModal";
|
import EditDeliveryModal from "@/components/modals/EditDeliveryModal";
|
||||||
import OrderDetailModal from "@/components/modals/OrderDetailModal";
|
import OrderDetailModal from "@/components/modals/OrderDetailModal";
|
||||||
|
import ValidateDeliveryModal from "@/components/modals/ValidateDeliveryModal";
|
||||||
import ConfirmDeleteModal from "@/components/modals/ConfirmDeleteModal";
|
import ConfirmDeleteModal from "@/components/modals/ConfirmDeleteModal";
|
||||||
import type { DeliveryWithRelations } from "@shared/schema";
|
import type { DeliveryWithRelations } from "@shared/schema";
|
||||||
|
|
||||||
@@ -67,8 +68,10 @@ export default function Deliveries() {
|
|||||||
const [showEditModal, setShowEditModal] = useState(false);
|
const [showEditModal, setShowEditModal] = useState(false);
|
||||||
const [showDetailModal, setShowDetailModal] = useState(false);
|
const [showDetailModal, setShowDetailModal] = useState(false);
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||||
|
const [showValidateModal, setShowValidateModal] = useState(false);
|
||||||
const [selectedDelivery, setSelectedDelivery] = useState<DeliveryWithRelations | null>(null);
|
const [selectedDelivery, setSelectedDelivery] = useState<DeliveryWithRelations | null>(null);
|
||||||
const [deliveryToDelete, setDeliveryToDelete] = useState<DeliveryWithRelations | null>(null);
|
const [deliveryToDelete, setDeliveryToDelete] = useState<DeliveryWithRelations | null>(null);
|
||||||
|
const [deliveryToValidate, setDeliveryToValidate] = useState<DeliveryWithRelations | null>(null);
|
||||||
|
|
||||||
// Construire l'URL pour l'historique complet sans filtrage par date
|
// 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
|
// 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 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({
|
const deleteMutation = useMutation({
|
||||||
mutationFn: async (id: number) => {
|
mutationFn: async (id: number) => {
|
||||||
@@ -231,10 +194,14 @@ export default function Deliveries() {
|
|||||||
setShowEditModal(true);
|
setShowEditModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleValidateDelivery = (id: number) => {
|
const handleValidateDelivery = (delivery: DeliveryWithRelations) => {
|
||||||
if (window.confirm("Êtes-vous sûr de vouloir valider cette livraison ?")) {
|
setDeliveryToValidate(delivery);
|
||||||
validateMutation.mutate(id);
|
setShowValidateModal(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const handleValidateModalClose = () => {
|
||||||
|
setShowValidateModal(false);
|
||||||
|
setDeliveryToValidate(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteDelivery = (delivery: DeliveryWithRelations) => {
|
const handleDeleteDelivery = (delivery: DeliveryWithRelations) => {
|
||||||
@@ -448,9 +415,9 @@ export default function Deliveries() {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleValidateDelivery(delivery.id)}
|
onClick={() => handleValidateDelivery(delivery)}
|
||||||
className="text-green-600 hover:text-green-700"
|
className="text-green-600 hover:text-green-700"
|
||||||
disabled={validateMutation.isPending}
|
disabled={false}
|
||||||
>
|
>
|
||||||
<Check className="w-4 h-4 border border-gray-300 rounded p-0.5" />
|
<Check className="w-4 h-4 border border-gray-300 rounded p-0.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -513,6 +480,14 @@ export default function Deliveries() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{showValidateModal && deliveryToValidate && (
|
||||||
|
<ValidateDeliveryModal
|
||||||
|
isOpen={showValidateModal}
|
||||||
|
onClose={handleValidateModalClose}
|
||||||
|
delivery={deliveryToValidate}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Modal de confirmation de suppression */}
|
{/* Modal de confirmation de suppression */}
|
||||||
<ConfirmDeleteModal
|
<ConfirmDeleteModal
|
||||||
isOpen={showDeleteModal}
|
isOpen={showDeleteModal}
|
||||||
|
|||||||
+8
-7
@@ -1113,13 +1113,14 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
|
|
||||||
const { blNumber, blAmount } = req.body;
|
const { blNumber, blAmount } = req.body;
|
||||||
|
|
||||||
// BL data is optional - delivery can be validated without it
|
// Le numéro de BL est maintenant obligatoire pour valider une livraison
|
||||||
let blData: any = undefined;
|
if (!blNumber || !blNumber.trim()) {
|
||||||
if (blNumber) {
|
return res.status(400).json({ message: "Le numéro de bon de livraison est obligatoire pour valider une livraison" });
|
||||||
blData = { blNumber };
|
}
|
||||||
if (blAmount !== undefined && blAmount !== null && blAmount !== '') {
|
|
||||||
blData.blAmount = blAmount;
|
let blData: any = { blNumber: blNumber.trim() };
|
||||||
}
|
if (blAmount !== undefined && blAmount !== null && blAmount !== '') {
|
||||||
|
blData.blAmount = blAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
await storage.validateDelivery(id, blData);
|
await storage.validateDelivery(id, blData);
|
||||||
|
|||||||
Reference in new issue
Block a user