Merge pull request #296 from R0m1k3/1.1

1.1
This commit is contained in:
LogiFlow authored and GitHub committed 2025-08-31 09:42:52 +02:00
commit ec2f61cf6f
6 files changed
+1364 -21

No files matched your search

-1
View File
@@ -37,4 +37,3 @@ args = "npm run dev"
waitForPort = 5000 waitForPort = 5000
[agent] [agent]
integrations = ["javascript_database==1.0.0"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

+60 -18
View File
@@ -24,25 +24,42 @@ export class InvoiceVerificationService {
const cached = await storage.getInvoiceVerificationCache(cacheKey); const cached = await storage.getInvoiceVerificationCache(cacheKey);
console.log('🔍 [CACHE] Résultat cache:', { console.log('🔍 [CACHE] Résultat cache:', {
found: !!cached, found: !!cached,
isReconciled: cached?.isReconciled,
expired: cached ? new Date() >= new Date(cached.expiresAt) : 'N/A', expired: cached ? new Date() >= new Date(cached.expiresAt) : 'N/A',
expiresAt: cached?.expiresAt, expiresAt: cached?.expiresAt,
currentTime: new Date().toISOString() currentTime: new Date().toISOString()
}); });
if (cached && new Date() < new Date(cached.expiresAt)) { // Cache permanent si facture validée (isReconciled = true)
console.log('✅ [CACHE] Cache hit pour:', { invoiceReference, groupId, exists: cached.exists }); if (cached && cached.isReconciled) {
console.log('✅ [CACHE] Cache PERMANENT pour facture validée:', { invoiceReference, groupId, exists: cached.exists });
return { return {
exists: cached.exists, exists: cached.exists,
matchType: cached.matchType, matchType: cached.matchType,
errorMessage: cached.errorMessage, errorMessage: cached.errorMessage,
invoiceReference: cached.invoiceReference, invoiceReference: cached.invoiceReference,
supplierName: cached.supplierName, supplierName: cached.supplierName,
fromCache: true fromCache: true,
permanent: true
};
}
// Cache temporaire non expiré
if (cached && new Date() < new Date(cached.expiresAt)) {
console.log('✅ [CACHE] Cache temporaire hit pour:', { invoiceReference, groupId, exists: cached.exists });
return {
exists: cached.exists,
matchType: cached.matchType,
errorMessage: cached.errorMessage,
invoiceReference: cached.invoiceReference,
supplierName: cached.supplierName,
fromCache: true,
permanent: false
}; };
} }
if (cached && new Date() >= new Date(cached.expiresAt)) { if (cached && new Date() >= new Date(cached.expiresAt)) {
console.log('⏰ [CACHE] Cache expiré pour:', { invoiceReference, groupId }); console.log('⏰ [CACHE] Cache temporaire expiré pour:', { invoiceReference, groupId });
} else { } else {
console.log('❌ [CACHE] Cache miss pour:', { invoiceReference, groupId }); console.log('❌ [CACHE] Cache miss pour:', { invoiceReference, groupId });
} }
@@ -55,19 +72,37 @@ export class InvoiceVerificationService {
} }
/** /**
* Sauvegarder dans le cache * Sauvegarder dans le cache avec durée adaptative
*/ */
async saveToCache(invoiceReference: string, groupId: number, result: any, supplierName?: string): Promise<void> { async saveToCache(invoiceReference: string, groupId: number, result: any, supplierName?: string, isReconciled: boolean = false): Promise<void> {
try { try {
const cacheKey = this.generateCacheKey(invoiceReference, groupId); const cacheKey = this.generateCacheKey(invoiceReference, groupId);
// Durée de cache adaptative selon les cas
const expiresAt = new Date(); const expiresAt = new Date();
expiresAt.setHours(expiresAt.getHours() + 24); // Cache pendant 24h let cacheDescription = '';
if (isReconciled) {
// Cache PERMANENT pour factures validées - expire dans 50 ans
expiresAt.setFullYear(expiresAt.getFullYear() + 50);
cacheDescription = 'PERMANENT (validé)';
} else if (result.exists) {
// Facture trouvée mais non validée - cache 6h pour permettre corrections
expiresAt.setHours(expiresAt.getHours() + 6);
cacheDescription = 'temporaire 6h (trouvé)';
} else {
// Facture non trouvée - cache 12h pour éviter spam
expiresAt.setHours(expiresAt.getHours() + 12);
cacheDescription = 'temporaire 12h (pas trouvé)';
}
console.log('💾 [CACHE] Tentative sauvegarde:', { console.log('💾 [CACHE] Tentative sauvegarde:', {
invoiceReference, invoiceReference,
groupId, groupId,
cacheKey, cacheKey,
exists: result.exists, exists: result.exists,
isReconciled,
cacheType: cacheDescription,
expiresAt: expiresAt.toISOString() expiresAt: expiresAt.toISOString()
}); });
@@ -81,6 +116,7 @@ export class InvoiceVerificationService {
errorMessage: result.errorMessage || null, errorMessage: result.errorMessage || null,
cacheHit: false, cacheHit: false,
apiCallTime: null, apiCallTime: null,
isReconciled, // Nouveau champ pour cache permanent
expiresAt expiresAt
}; };
@@ -91,6 +127,8 @@ export class InvoiceVerificationService {
invoiceReference, invoiceReference,
groupId, groupId,
exists: result.exists, exists: result.exists,
isReconciled,
cacheType: cacheDescription,
cacheKey cacheKey
}); });
} catch (error) { } catch (error) {
@@ -111,7 +149,7 @@ export class InvoiceVerificationService {
/** /**
* Vérifie une référence de facture pour un groupe donné * Vérifie une référence de facture pour un groupe donné
*/ */
async verifyInvoice(invoiceReference: string, groupId: number, forceRefresh: boolean = false): Promise<{ async verifyInvoice(invoiceReference: string, groupId: number, forceRefresh: boolean = false, isReconciled: boolean = false): Promise<{
exists: boolean; exists: boolean;
matchType: 'invoice_reference' | 'bl_number' | 'none'; matchType: 'invoice_reference' | 'bl_number' | 'none';
errorMessage?: string; errorMessage?: string;
@@ -186,7 +224,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder en cache // Sauvegarder en cache
await this.saveToCache(invoiceReference, groupId, result, result.supplierName); await this.saveToCache(invoiceReference, groupId, result, result.supplierName, isReconciled);
return result; return result;
} }
@@ -200,7 +238,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder en cache // Sauvegarder en cache
await this.saveToCache(invoiceReference, groupId, result, result.supplierName); await this.saveToCache(invoiceReference, groupId, result, result.supplierName, isReconciled);
return result; return result;
} }
@@ -211,7 +249,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder même les résultats "non trouvé" pour éviter les rappels répétés // Sauvegarder même les résultats "non trouvé" pour éviter les rappels répétés
await this.saveToCache(invoiceReference, groupId, result); await this.saveToCache(invoiceReference, groupId, result, undefined, isReconciled);
return result; return result;
} }
@@ -262,7 +300,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder en cache même les erreurs pour éviter les rappels répétés // Sauvegarder en cache même les erreurs pour éviter les rappels répétés
await this.saveToCache(invoiceReference, groupId, result); await this.saveToCache(invoiceReference, groupId, result, undefined, isReconciled);
return result; return result;
} }
@@ -276,7 +314,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder en cache si succès // Sauvegarder en cache si succès
await this.saveToCache(invoiceReference, groupId, result, result.supplierName); await this.saveToCache(invoiceReference, groupId, result, result.supplierName, isReconciled);
return result; return result;
} }
@@ -298,7 +336,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder en cache même les erreurs // Sauvegarder en cache même les erreurs
await this.saveToCache(invoiceReference, groupId, result); await this.saveToCache(invoiceReference, groupId, result, undefined, isReconciled);
return result; return result;
} }
@@ -312,7 +350,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder en cache si succès // Sauvegarder en cache si succès
await this.saveToCache(invoiceReference, groupId, result, result.supplierName); await this.saveToCache(invoiceReference, groupId, result, result.supplierName, isReconciled);
return result; return result;
} }
} }
@@ -325,7 +363,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder même les résultats "non trouvé" pour éviter les rappels répétés // Sauvegarder même les résultats "non trouvé" pour éviter les rappels répétés
await this.saveToCache(invoiceReference, groupId, notFoundResult); await this.saveToCache(invoiceReference, groupId, notFoundResult, undefined, isReconciled);
return notFoundResult; return notFoundResult;
} catch (error) { } catch (error) {
@@ -345,7 +383,7 @@ export class InvoiceVerificationService {
}; };
// Sauvegarder les erreurs en cache pour éviter les rappels répétés // Sauvegarder les erreurs en cache pour éviter les rappels répétés
await this.saveToCache(invoiceReference, groupId, errorResult); await this.saveToCache(invoiceReference, groupId, errorResult, undefined, isReconciled);
return errorResult; return errorResult;
} }
@@ -468,7 +506,7 @@ export class InvoiceVerificationService {
/** /**
* Vérifie une facture par numéro de BL et nom de fournisseur * Vérifie une facture par numéro de BL et nom de fournisseur
*/ */
async verifyInvoiceByBL(blNumber: string, supplierName: string, groupId: number, forceRefresh: boolean = false): Promise<{ async verifyInvoiceByBL(blNumber: string, supplierName: string, groupId: number, forceRefresh: boolean = false, isReconciled: boolean = false): Promise<{
exists: boolean; exists: boolean;
matchType: 'invoice_reference' | 'bl_number' | 'none'; matchType: 'invoice_reference' | 'bl_number' | 'none';
errorMessage?: string; errorMessage?: string;
@@ -638,6 +676,7 @@ export class InvoiceVerificationService {
errorMessage: result.errorMessage, errorMessage: result.errorMessage,
cacheHit: false, cacheHit: false,
apiCallTime: null, apiCallTime: null,
isReconciled,
expiresAt expiresAt
}); });
} catch (error) { } catch (error) {
@@ -688,6 +727,7 @@ export class InvoiceVerificationService {
errorMessage: null, errorMessage: null,
cacheHit: false, cacheHit: false,
apiCallTime: null, apiCallTime: null,
isReconciled,
expiresAt expiresAt
}); });
} catch (error) { } catch (error) {
@@ -719,6 +759,7 @@ export class InvoiceVerificationService {
errorMessage: notFoundResult.errorMessage, errorMessage: notFoundResult.errorMessage,
cacheHit: false, cacheHit: false,
apiCallTime: null, apiCallTime: null,
isReconciled,
expiresAt expiresAt
}); });
} catch (error) { } catch (error) {
@@ -753,6 +794,7 @@ export class InvoiceVerificationService {
errorMessage: errorResult.errorMessage, errorMessage: errorResult.errorMessage,
cacheHit: false, cacheHit: false,
apiCallTime: null, apiCallTime: null,
isReconciled,
expiresAt expiresAt
}); });
} catch (error) { } catch (error) {
+4 -2
View File
@@ -1053,7 +1053,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
result = await invoiceVerificationService.verifyInvoice( result = await invoiceVerificationService.verifyInvoice(
invoiceReference, invoiceReference,
delivery.groupId, delivery.groupId,
forceRefresh || false forceRefresh || false,
delivery.reconciled || false
); );
} else if (blNumber && blNumber.trim()) { } else if (blNumber && blNumber.trim()) {
// Vérifier par numéro BL // Vérifier par numéro BL
@@ -1061,7 +1062,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
blNumber, blNumber,
delivery.supplier.name, delivery.supplier.name,
delivery.groupId, delivery.groupId,
forceRefresh || false forceRefresh || false,
delivery.reconciled || false
); );
} else { } else {
result = { result = {
+1
View File
@@ -171,6 +171,7 @@ export const invoiceVerificationCache = pgTable("invoice_verification_cache", {
errorMessage: text("error_message"), errorMessage: text("error_message"),
cacheHit: boolean("cache_hit").default(false), cacheHit: boolean("cache_hit").default(false),
apiCallTime: integer("api_call_time"), apiCallTime: integer("api_call_time"),
isReconciled: boolean("is_reconciled").default(false), // Si true, cache permanent
expiresAt: timestamp("expires_at").notNull(), expiresAt: timestamp("expires_at").notNull(),
createdAt: timestamp("created_at").defaultNow(), createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(), updatedAt: timestamp("updated_at").defaultNow(),