From 80ca426a33c9998d1080c75dceb0b4d6151af62a Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Fri, 15 Aug 2025 09:48:29 +0000 Subject: [PATCH] Improve invoice verification caching with conflict resolution and error handling Implement unique constraint on invoice verification cache key and handle duplicate entries gracefully in the backend. Replit-Commit-Author: Agent Replit-Commit-Session-Id: d43bd811-9372-45a7-8ac9-4a954c0538e1 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/d43bd811-9372-45a7-8ac9-4a954c0538e1/g5c0JYM --- replit.md | 1 + server/invoiceVerification.ts | 5 +++++ server/storage.ts | 24 ++++++++++++++++++++++-- shared/schema.ts | 2 +- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/replit.md b/replit.md index bf9446d..b4ff2cc 100644 --- a/replit.md +++ b/replit.md @@ -32,6 +32,7 @@ The platform is built with a clear separation of concerns, utilizing a modern fu - **Weather Integration:** A comprehensive, modern weather interface displays detailed weather conditions sourced directly from the Visual Crossing API with French language support. Features intelligent date comparison using the same day of the week from the previous year for more relevant weather pattern analysis (e.g., Friday August 15, 2025 vs Friday August 16, 2024). - **Order and Delivery Management:** Full CRUD operations for orders and deliveries, including linking orders to deliveries and managing their statuses. - **Reconciliation:** Functionality for reconciling Bills of Lading (BL) and invoices with immediate UI updates. +- **Invoice Verification Cache:** Robust caching system for invoice verification results with automatic expiration and conflict resolution. Enhanced with unique constraint handling and graceful error management for production stability (August 2025). - **User and Permission Management:** Granular access controls ensuring that users (e.g., employees) have appropriate permissions for tasks like creating customer orders. - **Reporting:** Statistical reporting, including monthly summaries of deliveries based on `deliveredDate`. diff --git a/server/invoiceVerification.ts b/server/invoiceVerification.ts index 48d402a..e2cabb3 100644 --- a/server/invoiceVerification.ts +++ b/server/invoiceVerification.ts @@ -64,6 +64,11 @@ export class InvoiceVerificationService { console.log('đŸ’Ÿ RĂ©sultat sauvĂ© en cache:', { invoiceReference, groupId, exists: result.exists }); } catch (error) { + // GĂ©rer spĂ©cifiquement les erreurs de contrainte unique (duplicate key) + if (error && typeof error === 'object' && 'code' in error && error.code === '23505') { + console.log('🔄 Cache dĂ©jĂ  existant pour cette clĂ©, ignorĂ©:', { invoiceReference, groupId }); + return; + } console.error('❌ Erreur sauvegarde cache:', error); } } diff --git a/server/storage.ts b/server/storage.ts index ddc126e..329b59c 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -1287,8 +1287,28 @@ export class DatabaseStorage implements IStorage { } async createInvoiceVerificationCache(cacheData: InsertInvoiceVerificationCache): Promise { - const [cache] = await db.insert(invoiceVerificationCache).values(cacheData).returning(); - return cache; + try { + // Utiliser UPSERT pour gĂ©rer les conflits de clĂ©s + const [cache] = await db + .insert(invoiceVerificationCache) + .values(cacheData) + .onConflictDoUpdate({ + target: invoiceVerificationCache.cacheKey, + set: { + exists: cacheData.exists, + matchType: cacheData.matchType, + errorMessage: cacheData.errorMessage, + cacheHit: cacheData.cacheHit, + apiCallTime: cacheData.apiCallTime, + updatedAt: new Date() + } + }) + .returning(); + return cache; + } catch (error) { + console.error('❌ Erreur crĂ©ation cache:', error); + throw error; + } } async saveInvoiceVerificationCache(cacheData: InsertInvoiceVerificationCache): Promise { diff --git a/shared/schema.ts b/shared/schema.ts index d7e31d5..fb440bf 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -160,7 +160,7 @@ export const nocodbConfig = pgTable("nocodb_config", { // Cache de vĂ©rification des factures export const invoiceVerificationCache = pgTable("invoice_verification_cache", { id: serial("id").primaryKey(), - cacheKey: varchar("cache_key", { length: 255 }).notNull(), + cacheKey: varchar("cache_key", { length: 255 }).notNull().unique(), groupId: integer("group_id").notNull(), invoiceReference: varchar("invoice_reference", { length: 255 }).notNull(), supplierName: varchar("supplier_name", { length: 255 }),