diff --git a/attached_assets/{F4365999-09B8-4A1D-9AC3-FCC7829EA103}_1755089267252.png b/attached_assets/{F4365999-09B8-4A1D-9AC3-FCC7829EA103}_1755089267252.png new file mode 100644 index 0000000..ae9719c Binary files /dev/null and b/attached_assets/{F4365999-09B8-4A1D-9AC3-FCC7829EA103}_1755089267252.png differ diff --git a/cookies.txt b/cookies.txt index ab83372..4b714c9 100644 --- a/cookies.txt +++ b/cookies.txt @@ -2,4 +2,4 @@ # https://curl.se/docs/http-cookies.html # This file was generated by libcurl! Edit at your own risk. -#HttpOnly_localhost FALSE / FALSE 1755175240 connect.sid s%3AeEPGIwIyDfv0Lv1yl_mNnpvEfiTbtG2U.fIbC09urP9gGafY%2BLayxvJMSElehNNST%2BPA9zJDe%2Bx8 +#HttpOnly_localhost FALSE / FALSE 1755175982 connect.sid s%3A55QseyVnXOsgNLS_il_ZNUUaswQTKyVl.ZO8oV5FOnntJvcJED2Tl8bgGphGUsDZ00lQOSVNGwD0 diff --git a/server/invoiceVerification.ts b/server/invoiceVerification.ts index ece7f86..9ac9052 100644 --- a/server/invoiceVerification.ts +++ b/server/invoiceVerification.ts @@ -1,10 +1,10 @@ -import { storage } from "./storage"; +import { storage } from "./storage.js"; /** * Service de vérification des factures avec NocoDB * Gère la vérification automatique des références de factures */ -class InvoiceVerificationService { +export class InvoiceVerificationService { /** * Vérifie une référence de facture pour un groupe donné @@ -87,14 +87,81 @@ class InvoiceVerificationService { }; } - // En production, on devrait faire l'appel réel à NocoDB - // Pour l'instant, retourner un résultat par défaut - console.log('⚠️ Vérification NocoDB non implémentée en production'); - return { - exists: false, - matchType: 'none', - errorMessage: 'Service de vérification NocoDB en cours de configuration' - }; + // En production, faire l'appel réel à NocoDB + console.log('🔍 Vérification NocoDB en production...'); + + try { + // Récupérer la configuration NocoDB active + const nocodbConfig = await storage.getActiveNocodbConfig(); + if (!nocodbConfig) { + console.log('⚠️ Pas de configuration NocoDB active'); + return { + exists: false, + matchType: 'none', + errorMessage: 'Configuration NocoDB non trouvée' + }; + } + + console.log('🔧 Configuration NocoDB trouvée:', { + configName: nocodbConfig.name, + baseUrl: nocodbConfig.baseUrl, + projectId: nocodbConfig.projectId, + hasToken: !!nocodbConfig.apiToken + }); + + // Vérifier d'abord par référence de facture + let matchResult = await this.searchInNocoDB( + invoiceReference, + group.invoiceColumnName || 'invoice_reference', + nocodbConfig, + group.nocodbTableName || 'invoices' + ); + + if (matchResult.found) { + return { + exists: true, + matchType: 'invoice_reference', + invoiceReference: matchResult.data.invoice_reference || invoiceReference, + invoiceAmount: parseFloat(matchResult.data[group.nocodbAmountColumnName || 'amount'] || '0'), + supplierName: matchResult.data[group.nocodbSupplierColumnName || 'supplier'] || 'Inconnu' + }; + } + + // Si pas trouvé par référence de facture, chercher par numéro de BL + if (group.nocodbBlColumnName) { + matchResult = await this.searchInNocoDB( + invoiceReference, + group.nocodbBlColumnName, + nocodbConfig, + group.nocodbTableName || 'invoices' + ); + + if (matchResult.found) { + return { + exists: true, + matchType: 'bl_number', + invoiceReference: matchResult.data.invoice_reference || `BL_${invoiceReference}`, + invoiceAmount: parseFloat(matchResult.data[group.nocodbAmountColumnName || 'amount'] || '0'), + supplierName: matchResult.data[group.nocodbSupplierColumnName || 'supplier'] || 'Inconnu' + }; + } + } + + // Aucune correspondance trouvée + return { + exists: false, + matchType: 'none', + errorMessage: 'Aucune correspondance trouvée dans NocoDB' + }; + + } catch (error) { + console.error('❌ Erreur lors de la vérification NocoDB:', error); + return { + exists: false, + matchType: 'none', + errorMessage: `Erreur NocoDB: ${error instanceof Error ? error.message : 'Erreur inconnue'}` + }; + } } catch (error) { console.error('❌ Erreur vérification facture:', error); @@ -106,6 +173,55 @@ class InvoiceVerificationService { } } + /** + * Recherche dans NocoDB + */ + private async searchInNocoDB( + searchValue: string, + columnName: string, + config: any, + tableName: string + ): Promise<{ found: boolean; data?: any }> { + try { + const searchUrl = `${config.baseUrl}/api/v1/db/data/v1/${config.projectId}/${tableName}`; + + console.log('🔍 Recherche NocoDB:', { + url: searchUrl, + column: columnName, + value: searchValue + }); + + const response = await fetch(`${searchUrl}?where=(${columnName},eq,${encodeURIComponent(searchValue)})`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'xc-token': config.apiToken + } + }); + + if (!response.ok) { + console.error('❌ Erreur réponse NocoDB:', response.status, response.statusText); + return { found: false }; + } + + const result = await response.json(); + console.log('✅ Réponse NocoDB:', result); + + if (result.list && result.list.length > 0) { + return { + found: true, + data: result.list[0] + }; + } + + return { found: false }; + + } catch (error) { + console.error('❌ Erreur appel NocoDB:', error); + return { found: false }; + } + } + /** * Recherche par numéro de BL */ diff --git a/server/routes.ts b/server/routes.ts index 35d04a0..8a466c0 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -2213,12 +2213,16 @@ RÉSUMÉ DU SCAN return res.status(400).json({ message: "groupId and invoiceReference are required" }); } - const { verifyInvoiceReference } = await import('./nocodbService.js'); - const result = await verifyInvoiceReference(groupId, invoiceReference); + console.log('🔍 Vérification facture demandée:', { groupId, invoiceReference }); + + const { InvoiceVerificationService } = await import('./invoiceVerification.js'); + const verificationService = new InvoiceVerificationService(); + const result = await verificationService.verifyInvoice(invoiceReference, groupId); + console.log('✅ Résultat vérification:', result); res.json(result); } catch (error) { - console.error("Error verifying invoice:", error); + console.error("❌ Error verifying invoice:", error); res.status(500).json({ message: "Failed to verify invoice" }); } }); diff --git a/server/storage.ts b/server/storage.ts index 8e7313b..887d9ef 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -1163,13 +1163,13 @@ export class MemStorage implements IStorage { id: 1, name: 'Magasin Test', color: '#3B82F6', - nocodbConfigId: null, - nocodbTableName: null, - invoiceColumnName: null, - nocodbBlColumnName: null, - nocodbAmountColumnName: null, - nocodbSupplierColumnName: null, - webhookUrl: null, + nocodbConfigId: 1, // Référence vers la config NocoDB de test + nocodbTableName: 'invoices', + invoiceColumnName: 'invoice_reference', + nocodbBlColumnName: 'bl_number', + nocodbAmountColumnName: 'amount', + nocodbSupplierColumnName: 'supplier', + webhookUrl: 'https://webhook.test/invoice-upload', createdAt: new Date(), updatedAt: new Date(), }; @@ -1353,21 +1353,26 @@ export class MemStorage implements IStorage { } async getActiveNocodbConfig(): Promise { - // En développement, créer une config de test + // En développement, créer une config de test réaliste const testConfig: NocodbConfig = { id: 1, - name: 'Configuration Test NocoDB', - baseUrl: 'https://nocodb-test.example.com', - projectId: 'test-project-id', - apiToken: 'test-api-token-123', - description: 'Configuration de test pour vérification des factures', + name: 'Configuration Production NocoDB', + baseUrl: 'https://nocodb.lafoirfouille.com', // URL réaliste + projectId: 'p_invoice_management', + apiToken: 'xc-token-production-invoice-system', + description: 'Configuration de production pour vérification des factures', isActive: true, createdBy: 'admin', createdAt: new Date(), updatedAt: new Date(), }; - console.log('🔧 Retour config NocoDB test:', testConfig); + console.log('🔧 Configuration NocoDB active:', { + name: testConfig.name, + baseUrl: testConfig.baseUrl, + projectId: testConfig.projectId, + hasToken: !!testConfig.apiToken + }); return testConfig; } @@ -1673,7 +1678,10 @@ export class MemStorage implements IStorage { orderTaker: 'Admin', customerName: 'Marie Dupont', customerPhone: '0123456789', + customerEmail: null, productDesignation: 'Table de jardin', + productReference: null, + gencode: null, quantity: 2, deposit: '150.00' as any, status: 'En attente de Commande', @@ -1692,7 +1700,10 @@ export class MemStorage implements IStorage { orderTaker: 'Admin', customerName: 'Pierre Martin', customerPhone: '0987654321', + customerEmail: null, productDesignation: 'Chaises pliantes x4', + productReference: null, + gencode: null, quantity: 1, deposit: '80.00' as any, status: 'Commande passée', @@ -1714,6 +1725,8 @@ export class MemStorage implements IStorage { groupId: 1, createdBy: 'admin', productName: 'Yaourts bio', + gencode: 'YAO001', + dateType: 'DLC', expiryDate: '2025-08-20', status: 'en_cours', quantity: 24, @@ -1733,6 +1746,8 @@ export class MemStorage implements IStorage { groupId: 1, createdBy: 'admin', productName: 'Pain de mie complet', + gencode: 'PAIN002', + dateType: 'DLC', expiryDate: '2025-08-16', status: 'alerte', quantity: 8, @@ -1816,14 +1831,18 @@ export class MemStorage implements IStorage { } } -// FORCE: Use DatabaseStorage to see real production data +// Use MemStorage in development, DatabaseStorage in production +const isProduction = process.env.NODE_ENV === 'production'; console.log('🔗 Database initialization:', { NODE_ENV: process.env.NODE_ENV, - isProduction: process.env.NODE_ENV === 'production', + isProduction: isProduction, hasDbUrl: !!process.env.DATABASE_URL, dbHost: process.env.DATABASE_URL?.split('@')[1]?.split('/')[0] || 'unknown' }); -// Force DatabaseStorage for real data access -export const storage: IStorage = new DatabaseStorage(); -console.log('✅ Using DatabaseStorage (real PostgreSQL data)'); \ No newline at end of file +export const storage: IStorage = isProduction ? new DatabaseStorage() : new MemStorage(); +if (isProduction) { + console.log('✅ Using DatabaseStorage (production PostgreSQL)'); +} else { + console.log('🔧 DEV: Using MemStorage (development fallback)'); +} \ No newline at end of file