feat: add bank file import as core, move Enable Banking to extension
Replace PSD2 bank integration as the default with file-based bank import (CSV/XML), which better suits Swedish sole traders and small companies. Enable Banking is now an opt-in extension. - Phase 1: Extract generic transaction ingestion service (ingest.ts) with dedup, auto-categorization, and OCR-based invoice matching - Phase 2: Bank file parser library supporting Nordea, SEB, Swedbank, Handelsbanken CSV formats and ISO 20022 camt.053 XML - Phase 3: Database migration adding import_source, reference columns and bank_file_imports tracking table - Phase 4: Import wizard UI (5-step flow) and API routes for parse/execute - Phase 5: Move Enable Banking to extensions/enable-banking/ with commented-out loader entry for opt-in activation - Phase 6: 104 new tests (ingestion + all parser formats), fixing Nordea detection overlap and camt.053 XML tag collision bugs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
838dc6b8b5
commit
885f362a29
@@ -11,6 +11,7 @@ export interface InvoiceMatch {
|
||||
* Confidence thresholds for invoice matching
|
||||
*/
|
||||
const CONFIDENCE = {
|
||||
OCR_REFERENCE_MATCH: 0.99,
|
||||
EXACT_AMOUNT_CUSTOMER: 0.95,
|
||||
EXACT_AMOUNT_ONLY: 0.80,
|
||||
FUZZY_AMOUNT_CUSTOMER: 0.70,
|
||||
@@ -144,6 +145,29 @@ export async function findMatchingInvoices(
|
||||
|
||||
const matches: InvoiceMatch[] = []
|
||||
|
||||
// OCR/Bankgiro reference matching — highest confidence
|
||||
// Swedish standard: match transaction reference to invoice OCR number
|
||||
const txReference = (transaction as Transaction & { reference?: string | null }).reference
|
||||
if (txReference) {
|
||||
const normalizedRef = txReference.replace(/\s+/g, '')
|
||||
for (const invoice of invoices) {
|
||||
// Match against invoice_number (used as OCR reference in Swedish payments)
|
||||
const invoiceRef = invoice.invoice_number?.replace(/\s+/g, '')
|
||||
if (invoiceRef && normalizedRef === invoiceRef) {
|
||||
matches.push({
|
||||
invoice: invoice as Invoice & { customer?: Customer },
|
||||
confidence: CONFIDENCE.OCR_REFERENCE_MATCH,
|
||||
matchReason: `OCR-referens matchar fakturanummer ${invoice.invoice_number}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// If we found an OCR match, return immediately (highest possible confidence)
|
||||
if (matches.length > 0) {
|
||||
return matches
|
||||
}
|
||||
}
|
||||
|
||||
for (const invoice of invoices) {
|
||||
// Currency filter - must match or be SEK equivalent
|
||||
const currencyMatch =
|
||||
|
||||
Reference in New Issue
Block a user