mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-11 17:27:31 +02:00
Merge pull request #88 from R0m1k3/1.1
Enable invoice verification using NocoDB for production environments
This commit is contained in:
5 files changed
+172
-33
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 543 KiB |
+1
-1
@@ -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
|
||||
+126
-10
@@ -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
|
||||
*/
|
||||
|
||||
+7
-3
@@ -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" });
|
||||
}
|
||||
});
|
||||
|
||||
+38
-19
@@ -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<NocodbConfig | undefined> {
|
||||
// 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)');
|
||||
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)');
|
||||
}
|
||||
Reference in new issue
Block a user