diff --git a/client/src/pages/Avoirs.tsx b/client/src/pages/Avoirs.tsx index 13d601a..046dd2e 100644 --- a/client/src/pages/Avoirs.tsx +++ b/client/src/pages/Avoirs.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; -import { Plus, Search, FileText, CheckCircle, AlertCircle, Clock, Edit, Trash2, UserCheck } from "lucide-react"; +import { Plus, Search, FileText, CheckCircle, AlertCircle, Clock, Edit, Trash2, UserCheck, Send } from "lucide-react"; import { useStore } from "@/components/Layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -159,7 +159,7 @@ export default function Avoirs() { // ✅ FIX: Invalider toutes les variations de queryKey avoirs queryClient.invalidateQueries({ predicate: (query) => { - return query.queryKey[0]?.toString().includes('/api/avoirs'); + return query.queryKey[0]?.toString().includes('/api/avoirs') || false; } }); setIsCreateDialogOpen(false); @@ -197,7 +197,7 @@ export default function Avoirs() { // ✅ FIX: Invalider toutes les variations de queryKey avoirs queryClient.invalidateQueries({ predicate: (query) => { - return query.queryKey[0]?.toString().includes('/api/avoirs'); + return query.queryKey[0]?.toString().includes('/api/avoirs') || false; } }); setIsEditDialogOpen(false); @@ -232,7 +232,7 @@ export default function Avoirs() { // ✅ FIX: Invalider toutes les variations de queryKey avoirs queryClient.invalidateQueries({ predicate: (query) => { - return query.queryKey[0]?.toString().includes('/api/avoirs'); + return query.queryKey[0]?.toString().includes('/api/avoirs') || false; } }); setIsDeleteDialogOpen(false); @@ -660,6 +660,11 @@ export default function Avoirs() { )} + {avoir.webhookSent && ( +
+ +
+ )} diff --git a/server/routes.ts b/server/routes.ts index 05f0cb0..320b74d 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -2508,6 +2508,51 @@ export async function registerRoutes(app: Express): Promise { const updatedAvoir = await storage.updateAvoir(id, validatedData); console.log('✅ Avoir updated:', id, 'by user:', user.id); + + // 🎯 WEBHOOK QUAND STATUT PASSE À "Reçu" + if (validatedData.status === 'Reçu' && existingAvoir.status !== 'Reçu') { + try { + // Utiliser groupe par défaut (1) pour admin si pas de groupe sélectionné + const groupId = updatedAvoir.groupId || (user.role === 'admin' ? 1 : updatedAvoir.groupId); + const group = await storage.getGroup(groupId); + + if (group && group.webhookUrl) { + const webhookData = { + type: "Avoir", + avoirId: updatedAvoir.id, + invoiceReference: updatedAvoir.invoiceReference, + amount: updatedAvoir.amount, + supplierName: "Fournisseur", // Sera enrichi avec relations + groupName: group.name, + comment: updatedAvoir.comment || "", + commercialProcessed: updatedAvoir.commercialProcessed, + status: "Reçu", + createdBy: user.firstName && user.lastName ? `${user.firstName} ${user.lastName}` : user.username, + processedAt: new Date().toISOString() + }; + + console.log('🌐 Envoi webhook avoir reçu:', { groupId, webhookUrl: group.webhookUrl }); + + const webhookResponse = await fetch(group.webhookUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(webhookData) + }); + + if (webhookResponse.ok) { + await storage.updateAvoirWebhookStatus(updatedAvoir.id, true); + console.log('✅ Webhook avoir reçu envoyé:', updatedAvoir.id); + } else { + console.error('❌ Échec envoi webhook avoir:', webhookResponse.status); + } + } + } catch (webhookError) { + console.error('❌ Erreur webhook avoir reçu:', webhookError); + } + } + res.json(updatedAvoir); } catch (error) { if (error instanceof z.ZodError) {