feat: implement date normalization utility and add BAP webhook configuration management routes

This commit is contained in:
Michael committed 2026-04-29 12:02:21 +02:00
1 parent 0255dc4aba
commit 79cd5d4f61
4 files changed
+90 -40

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
import fetch from 'node-fetch';
import FormData from 'form-data';
const webhookUrl = 'https://workflow.ffnancy.fr/webhook-test/acf9cbf7-040a-4cf5-a43d-80210420d30a';
async function testWebhook() {
console.log('🚀 Testing webhook:', webhookUrl);
const formData = new FormData();
formData.append('file', Buffer.from('test content'), {
filename: 'test.txt',
contentType: 'text/plain'
});
formData.append('supplier', 'Test Supplier');
formData.append('blNumber', '12345');
formData.append('type', 'Facture');
try {
const response = await fetch(webhookUrl, {
method: 'POST',
body: formData,
headers: formData.getHeaders()
});
console.log('📡 Response status:', response.status);
const text = await response.text();
console.log('📄 Response body:', text);
} catch (error) {
console.error('❌ Error calling webhook:', error);
}
}
testWebhook();
+27
View File
@@ -0,0 +1,27 @@
const webhookUrl = 'https://workflow.ffnancy.fr/webhook-test/acf9cbf7-040a-4cf5-a43d-80210420d30a';
async function testWebhook() {
console.log('🚀 Testing webhook (Native Fetch/FormData):', webhookUrl);
const formData = new FormData();
const fileBlob = new Blob(['test content'], { type: 'text/plain' });
formData.append('file', fileBlob, 'test.txt');
formData.append('supplier', 'Test Supplier');
formData.append('blNumber', '12345');
formData.append('type', 'Facture');
try {
const response = await fetch(webhookUrl, {
method: 'POST',
body: formData
});
console.log('📡 Response status:', response.status);
const text = await response.text();
console.log('📄 Response body:', text);
} catch (error) {
console.error('❌ Error calling webhook:', error);
}
}
testWebhook();
+12 -14
View File
@@ -6,7 +6,8 @@ import { requireModulePermission, requireAdmin, requirePermission } from "./perm
import { db, pool } from "./db";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const FormData = require('form-data');
// Suppression de l'import form-data car nous utilisons le FormData natif de Node.js 18+
// const FormData = require('form-data');
console.log('🔍 Using development storage and authentication');
@@ -861,8 +862,10 @@ export async function registerRoutes(app: Express): Promise<Server> {
// Parser le multipart/form-data manuellement
const contentType = req.headers['content-type'] || '';
const boundaryMatch = contentType.match(/boundary=(.+)$/);
// Gestion plus robuste du boundary (avec ou sans guillemets)
const boundaryMatch = contentType.match(/boundary="?([^";]+)"?/i);
if (!boundaryMatch) {
console.error('❌ INVOICE PROXY: Boundary manquant dans Content-Type', contentType);
return res.status(400).json({ error: 'Format multipart invalide' });
}
@@ -889,27 +892,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
size: parts.file.buffer.length
});
// Import dynamique standard pour ESM (sans eval)
console.log('🔍 INVOICE PROXY: FormData loaded', {
type: typeof FormData,
isConstructor: typeof FormData === 'function'
});
// Utilisation du FormData natif de Node.js (global)
// On utilise Blob pour transformer le Buffer en objet compatible
const formData = new FormData();
formData.append('file', parts.file.buffer, {
filename: parts.file.filename,
contentType: parts.file.contentType
});
const fileBlob = new Blob([parts.file.buffer], { type: parts.file.contentType });
formData.append('file', fileBlob, parts.file.filename);
formData.append('supplier', parts.supplier || '');
formData.append('blNumber', parts.blNumber || '');
formData.append('type', parts.type || 'Facture');
console.log('🔗 INVOICE PROXY: Calling webhook URL:', parts.webhookUrl);
// En utilisant le FormData natif avec fetch, pas besoin de headers manuels (boundary géré automatiquement)
const response = await fetch(parts.webhookUrl, {
method: 'POST',
body: formData as any,
headers: formData.getHeaders()
body: formData as any
});
if (!response.ok) {
+18 -26
View File
@@ -1,38 +1,30 @@
# Task: Correction blocage API Publicités
# Task: Debugging Webhook Error 500 on Invoice Sending
## Context
L'utilisateur rencontre une erreur `net::ERR_BLOCKED_BY_CLIENT` lors de l'appel à l'API `/api/publicities`. Cette erreur est typique des bloqueurs de publicité (AdBlock, uBlock) qui filtrent les requêtes contenant des mots-clés comme "publicity" ou "ads".
L'utilisateur a redémarré son serveur et rencontre une erreur 500 lors de l'envoi d'une facture via le proxy `/api/reconciliation/send-invoice`. L'appel vers le webhook N8N (`https://workflow.ffnancy.fr/webhook/...`) échoue avec un code 500.
## Current Focus
Renommer les endpoints API pour éviter le blocage par les bloqueurs de publicité.
Identifier la cause de l'erreur 500 lors de l'appel au webhook N8N et corriger le comportement du proxy de facture.
## Master Plan
- [x] **Remplacement des API calls (Client-side)**
- [x] `client/src/pages/Calendar.tsx`
- [x] `client/src/pages/Dashboard.tsx`
- [x] `client/src/components/PublicityForm.tsx`
- [x] `client/src/pages/Publicities.tsx`
- [x] `client/src/pages/mobile/PublicitiesPage.tsx`
- [x] **Revue du sélecteur d'année Mobile**
- [x] Vérifier la logique de génération des années dans `client/src/pages/mobile/PublicitiesPage.tsx` pour inclure les années passées (ex: 2024 en 2026).
- [x] Aligner avec la correction desktop si nécessaire.
- [x] **Correction des erreurs Lint TypeScript**
- [x] Installer les paquets `@types` manquants (`node`, `express`, `react`, etc.).
- [x] Fixer les paramètres `req` et `res` (implicitement `any`) dans `server/routes.ts`.
- [x] Corriger l'erreur de propriété `invoiceAmountTTC` dans `server/routes.ts`.
- [x] Résoudre `Property 'env' does not exist on type 'ImportMeta'`.
- [x] Résoudre `JSX element implicitly has type 'any'`.
- [x] **Tests et Validation**
- [x] Vérifier que les appels API utilisent bien `/api/ad-campaigns`.
- [x] Tester le sélecteur d'année sur mobile.
- [x] Compiler le projet (`npm run check`) pour s'assurer que les erreurs critiques sont résolues.
- [x] **Analyse du code source**
- [x] Examiner `server/routes.ts` pour trouver l'endpoint `/api/reconciliation/send-invoice`.
- [x] Analyser la construction de la requête vers N8N (utilisation de `FormData` natif vs bibliothèque `form-data`).
- [x] **Investigation technique**
- [x] Vérifier la version de Node.js (v24.11.1 détectée).
- [x] Identifier pourquoi N8N renvoie 500 (problème de format multipart et de headers avec l'ancienne bibliothèque).
- [x] Prendre en compte l'URL de test fournie : `https://workflow.ffnancy.fr/webhook-test/...`.
- [x] **Correction et Test**
- [x] Remplacer l'implémentation personnalisée par une utilisation plus propre des APIs natives Node.js.
- [x] Améliorer le parsing du boundary pour gérer les guillemets.
- [x] Utiliser les APIs natives `fetch` et `FormData` de Node.js pour plus de robustesse.
- [ ] Demander à l'utilisateur de tester après avoir reconstruit son image Docker.
## Progress Log
- Création de la tâche suite aux logs fournis.
- Initialisation de la tâche pour déboguer l'erreur 500 sur l'envoi de facture.
- Analyse du code : le proxy utilisait une ancienne bibliothèque `form-data` manuellement importée via `require`, ce qui peut causer des problèmes de compatibilité en Node 24.
- Correction appliquée : passage aux APIs natives `fetch` et `FormData` de Node.js et amélioration du parsing du boundary.