feat: unified document inbox, full BAS 2026, and document-transaction matching

- Expand BAS reference from ~180 to ~1,276 accounts (full BAS Kontoplan 2026)
  with K2 exclusion flags, per-class data files, and computed SRU codes
- Evolve invoice inbox into unified document inbox handling invoices, receipts,
  and government letters with AI-powered classification (Claude Haiku Vision)
- Add multi-pass document-to-transaction matching engine with greedy assignment
  for both supplier invoices (reference/amount/date/name) and receipts
  (weighted amount/merchant/date scoring)
- Add supplier invoice matching in transaction ingest pipeline
- Inject booking template suggestions into AI extraction prompts
- Surface matched documents in swipe categorization UI with one-tap booking
- Auto-activate missing BAS accounts during SIE import against full reference
- Add K2 filter toggle in Chart of Accounts manager
- Add receipt confirmation route with BFNAR representation fields
- Add database migrations for K2 support and document matching columns
- Remove obsolete extension migration scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-02-25 16:59:02 +01:00
co-authored by Claude Opus 4.6
parent 6956a757f3
commit 39e407644d
68 changed files with 19234 additions and 2412 deletions
+41 -1
View File
@@ -1,4 +1,4 @@
import type { InboxItemStatus, InvoiceExtractionResult } from '@/types'
import type { InboxItemStatus, InvoiceExtractionResult, DocumentClassificationType } from '@/types'
const STATUS_LABELS: Record<InboxItemStatus, string> = {
pending: 'Väntar',
@@ -51,3 +51,43 @@ export function formatExtractionSummary(
lineCount: data.lineItems?.length ?? 0,
}
}
// Document type labels (Swedish)
const DOCUMENT_TYPE_LABELS: Record<DocumentClassificationType, string> = {
supplier_invoice: 'Faktura',
receipt: 'Kvitto',
government_letter: 'Myndighetspost',
unknown: 'Övrigt',
}
export function getDocumentTypeLabel(type: DocumentClassificationType): string {
return DOCUMENT_TYPE_LABELS[type] ?? type
}
const DOCUMENT_TYPE_VARIANTS: Record<DocumentClassificationType, string> = {
supplier_invoice: 'default',
receipt: 'secondary',
government_letter: 'outline',
unknown: 'outline',
}
export function getDocumentTypeVariant(type: DocumentClassificationType): string {
return DOCUMENT_TYPE_VARIANTS[type] ?? 'outline'
}
/**
* Format extraction summary for receipt documents
*/
export function formatReceiptSummary(
data: Record<string, unknown> | null | undefined
): { merchantName: string; total: number } {
if (!data) {
return { merchantName: '', total: 0 }
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const d = data as any
return {
merchantName: d.merchant?.name ?? '',
total: d.totals?.total ?? 0,
}
}
+3 -3
View File
@@ -72,15 +72,15 @@ export const SECTORS: Sector[] = [
},
{
slug: 'invoice-inbox',
name: 'Leverantörsfaktura-inbox',
name: 'Dokumentinkorg',
sector: 'general',
category: 'import',
icon: 'Inbox',
dataPattern: 'manual',
hasOwnData: true,
description: 'Ta emot leverantörsfakturor via e-post eller uppladdning',
description: 'Ta emot alla dokument via e-post — fakturor, kvitton och myndighetspost',
longDescription:
'Skicka leverantörsfakturor till en dedikerad e-postadress eller ladda upp manuellt. AI extraherar automatiskt leverantörsdata, belopp och moms. Granska och bekräfta med ett klick för att skapa leverantörsfakturor.',
'Skicka alla affärsdokument till en dedikerad e-postadress. AI klassificerar automatiskt dokumenttyp (faktura, kvitto, myndighetspost), extraherar data och matchar mot transaktioner. En inkorg för alla dokument.',
},
{
slug: 'calendar',
+1 -1
View File
@@ -13,7 +13,7 @@ const WORKSPACES: Record<WorkspaceKey, ComponentType<WorkspaceComponentProps>> =
'general/ai-categorization': dynamic(() => import('@/components/extensions/general/AiCategorizationWorkspace')),
'general/ai-chat': dynamic(() => import('@/components/extensions/general/AiChatWorkspace')),
'general/push-notifications': dynamic(() => import('@/components/extensions/general/PushNotificationsWorkspace')),
'general/invoice-inbox': dynamic(() => import('@/components/extensions/general/InvoiceInboxWorkspace')),
'general/invoice-inbox': dynamic(() => import('@/components/extensions/general/DocumentInboxWorkspace')),
'general/calendar': dynamic(() => import('@/components/extensions/general/CalendarWorkspace')),
'general/enable-banking': dynamic(() => import('@/components/extensions/general/EnableBankingWorkspace')),
'general/user-description-match': dynamic(() => import('@/components/extensions/general/UserDescriptionMatchWorkspace')),