Skip to Content
TecnicaFunzionalitaMiglioramenti Auto-Match AI - Movimenti Bancari

Miglioramenti Auto-Match AI - Movimenti Bancari

Problemi Risolti

1. Fornitore non inserito automaticamente

Problema: Il fornitore estratto dall’AI non veniva salvato se non c’era un match con le fatture.

Soluzione: Ora il supplierName viene salvato immediatamente dopo l’estrazione, indipendentemente dal match con le fatture. Questo permette di mantenere il fornitore anche per transazioni senza fatture corrispondenti.

2. Amazon (AMZN) non riconosciuto

Problema: Le transazioni con “AMZN” nella descrizione non venivano abbinate al fornitore Amazon.

Soluzione:

  • Aggiunta una mappa di abbreviazioni comuni che espande automaticamente:
    • AMZNAmazon
    • AMZAmazon
    • METROMetro
    • etc.
  • Il prompt AI ora riceve sia la descrizione originale che quella espansa
  • Aggiunti esempi espliciti nel prompt AI per gestire AMZN/AMZ

3. Matching fornitori troppo rigido

Problema: Il matching tra transazioni e fatture falliva con piccole variazioni nei nomi (es. “Metro” vs “Metro Cash & Carry”).

Soluzione: Implementato matching più flessibile:

  • Rimozione automatica di suffissi comuni (SRL, SPA, SAS, Ltd, Inc, LLC)
  • Match bidirezionale (uno contiene l’altro)
  • Match per parole chiave significative (>3 caratteri)
  • Match case-insensitive

4. Abbinamento fatture prima del completamento estrazione fornitori

Problema: Il matching delle fatture iniziava prima che tutti i fornitori fossero stati estratti e salvati.

Soluzione:

  • Salvataggio parallelo di tutti i fornitori tramite Promise.all()
  • Log di conferma quando tutti i fornitori sono salvati
  • Separazione chiara tra fase di estrazione e fase di matching
  • Il matching inizia solo dopo che TUTTI i fornitori sono stati identificati e salvati

Modifiche Tecniche

File modificato

/src/app/api/bank-transactions/auto-match/route.ts

Cambiamenti principali

  1. Mappa abbreviazioni (linea ~420):
const supplierAbbreviations: Record<string, string> = { AMZN: "Amazon", AMZ: "Amazon", AMAZON: "Amazon", METRO: "Metro", SYSCO: "Sysco", };
  1. Espansione descrizioni (linea ~428):
const expandAbbreviations = (description: string): string => { let expanded = description; for (const [abbr, fullName] of Object.entries(supplierAbbreviations)) { const regex = new RegExp(`\\b${abbr}\\b`, "gi"); expanded = expanded.replace(regex, fullName); } return expanded; };
  1. Salvataggio parallelo e completo dei fornitori (linea ~500):
// Salva i fornitori estratti IMMEDIATAMENTE in parallelo const savePromises = []; for (const extraction of extractionResult.extractions || []) { const transaction = supplierPayments.find( (t: any) => t._id.toString() === extraction.id, ); if (transaction && extraction.supplierName) { transaction.supplierName = extraction.supplierName; savePromises.push( transaction.save().then(() => { sendLog(`Fornitore estratto e salvato: ${extraction.supplierName}...`); }), ); } } // Aspetta che TUTTI i fornitori siano salvati prima di procedere await Promise.all(savePromises); sendLog(`Completato salvataggio di ${savePromises.length} fornitori estratti`);
  1. Separazione chiara tra estrazione e matching (linea ~525):
// IMPORTANTE: A questo punto tutti i fornitori sono stati estratti e salvati // Ora possiamo procedere con l'abbinamento delle fatture sendLog("Inizio abbinamento fatture ai fornitori identificati..."); for (const transaction of supplierPayments) { // ... logica di matching }
  1. Matching fornitori migliorato (linea ~570):
// Rimuovi suffissi comuni per il matching const cleanSupplier = (name: string) => name .replace(/\s+(s\.?r\.?l\.?|s\.?p\.?a\.?|s\.?a\.?s\.?|ltd|inc|llc)$/gi, "") .trim(); const cleanTransaction = cleanSupplier(transactionSupplier); const cleanInvoice = cleanSupplier(invoiceSupplier); // Match se uno contiene l'altro o se sono molto simili const supplierMatch = invoiceSupplier.includes(transactionSupplier) || transactionSupplier.includes(invoiceSupplier) || cleanInvoice.includes(cleanTransaction) || cleanTransaction.includes(cleanInvoice) || // Match per parole chiave transactionSupplier .split(/\s+/) .some(word => word.length > 3 && invoiceSupplier.includes(word)) || invoiceSupplier .split(/\s+/) .some(word => word.length > 3 && transactionSupplier.includes(word));

Esempi di Miglioramenti

Prima delle modifiche:

  • ❌ “AMZN EU SARL” → Nessun fornitore
  • ❌ “PAGAMENTO METRO” → Nessun match con “Metro Cash & Carry”
  • ❌ Fornitore estratto ma non salvato se manca fattura

Dopo le modifiche:

  • ✅ “AMZN EU SARL” → Fornitore: “Amazon”
  • ✅ “PAGAMENTO METRO” → Match con “Metro Cash & Carry”
  • ✅ Fornitore sempre salvato, anche senza fattura corrispondente

Note per Estensioni Future

Per aggiungere nuove abbreviazioni comuni, modificare la mappa supplierAbbreviations:

const supplierAbbreviations: Record<string, string> = { AMZN: "Amazon", AMZ: "Amazon", METRO: "Metro", // Aggiungi qui nuove abbreviazioni ABBREVIAZIONE: "Nome Completo", };

Testing

Testare con:

  1. Transazioni con “AMZN” nella descrizione
  2. Fornitori con nomi abbreviati vs nomi completi nelle fatture
  3. Verificare che il fornitore venga salvato anche senza match di fatture
Last updated on