mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-22 14:38:19 +02:00
6 files changed
+1364
-21
No files matched your search
@@ -37,4 +37,3 @@ args = "npm run dev"
|
|||||||
waitForPort = 5000
|
waitForPort = 5000
|
||||||
|
|
||||||
[agent]
|
[agent]
|
||||||
integrations = ["javascript_database==1.0.0"]
|
|
||||||
+1299
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
@@ -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
@@ -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 = {
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
Reference in new issue
Block a user