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:
co-authored by
Claude Opus 4.6
parent
6956a757f3
commit
39e407644d
@@ -46,10 +46,19 @@ export interface CategorizationContext {
|
||||
recentHistory: { description: string; category: string }[]
|
||||
}
|
||||
|
||||
export interface DocumentEnrichment {
|
||||
type: 'receipt' | 'supplier_invoice'
|
||||
merchantName?: string
|
||||
lineItems?: Array<{ description: string; amount: number; category?: string; accountSuggestion?: string }>
|
||||
vatBreakdown?: Array<{ rate: number; amount: number }>
|
||||
isReverseCharge?: boolean
|
||||
}
|
||||
|
||||
export interface EnrichedCategorizationContext extends CategorizationContext {
|
||||
candidateTemplates: BookingTemplate[]
|
||||
userAccountUsage: AccountUsageEntry[]
|
||||
merchantHistory: MerchantHistoryEntry[]
|
||||
documentData?: DocumentEnrichment
|
||||
}
|
||||
|
||||
export interface CategorizationSuggestion {
|
||||
@@ -223,6 +232,11 @@ export class AnthropicCategorizationProvider implements CategorizationProvider {
|
||||
.join('\n')}`
|
||||
: ''
|
||||
|
||||
// Build document enrichment context (from linked receipt or supplier invoice)
|
||||
const documentContext = enriched?.documentData
|
||||
? buildDocumentContext(enriched.documentData)
|
||||
: ''
|
||||
|
||||
const systemPrompt = `Du är expert på svensk bokföring och kategorisering av banktransaktioner enligt BAS-kontoplanen.
|
||||
Din uppgift är att kategorisera varje transaktion till rätt mall-ID (templateId) och BAS-konto.
|
||||
|
||||
@@ -243,7 +257,7 @@ MOMSHANTERING:
|
||||
- Intäkter: Normalt 25% moms (utgående moms, MP1)
|
||||
|
||||
${NON_DEDUCTIBLE_RULES}
|
||||
|
||||
${documentContext}
|
||||
REGLER:
|
||||
1. Negativa belopp = utgifter, positiva = intäkter
|
||||
2. VIKTIGT: Dessa transaktioner kommer från företagets bankkonto/kort. Anta ALLTID att de är affärsrelaterade. Klassificera ALDRIG som "private" — det beslutet tar användaren själv.
|
||||
@@ -382,6 +396,42 @@ ${transactionList}`
|
||||
}
|
||||
}
|
||||
|
||||
function buildDocumentContext(doc: DocumentEnrichment): string {
|
||||
const parts: string[] = []
|
||||
|
||||
const typeLabel = doc.type === 'receipt' ? 'KVITTO' : 'LEVERANTÖRSFAKTURA'
|
||||
parts.push(`LÄNKAT DOKUMENT (${typeLabel}):`)
|
||||
|
||||
if (doc.merchantName) {
|
||||
parts.push(`Handlare/leverantör: ${doc.merchantName}`)
|
||||
}
|
||||
|
||||
if (doc.lineItems && doc.lineItems.length > 0) {
|
||||
parts.push('Rader:')
|
||||
for (const item of doc.lineItems) {
|
||||
let line = `- ${item.description}: ${item.amount} kr`
|
||||
if (item.accountSuggestion) line += ` (föreslaget konto: ${item.accountSuggestion})`
|
||||
if (item.category) line += ` [${item.category}]`
|
||||
parts.push(line)
|
||||
}
|
||||
}
|
||||
|
||||
if (doc.vatBreakdown && doc.vatBreakdown.length > 0) {
|
||||
parts.push('Momsfördelning:')
|
||||
for (const vat of doc.vatBreakdown) {
|
||||
parts.push(`- ${vat.rate}%: ${vat.amount} kr`)
|
||||
}
|
||||
}
|
||||
|
||||
if (doc.isReverseCharge) {
|
||||
parts.push(`VIKTIGT: Omvänd skattskyldighet (reverse charge). Använd dubbelkontering:
|
||||
- Debitera 2645 (beräknad ingående moms) OCH kreditera 2614 (utgående moms, omvänd skattskyldighet)
|
||||
- Mallen "purchase_eu_service_reverse_charge" ska användas om tillgänglig`)
|
||||
}
|
||||
|
||||
return parts.join('\n') + '\n'
|
||||
}
|
||||
|
||||
function isEnrichedContext(
|
||||
ctx: CategorizationContext | EnrichedCategorizationContext
|
||||
): ctx is EnrichedCategorizationContext {
|
||||
|
||||
Reference in New Issue
Block a user