Files
accounted/lib/bookkeeping/booking-templates.ts
T
Jakob WennbergandClaude Opus 4.6 bbb82866ee feat: add 4 new Swedish bank CSV parsers and improve transaction categorization
Add auto-detecting CSV parsers for Länsförsäkringar, ICA Banken, Skandia,
and Lunar. Refine SEB detection to avoid false matches. Update bank file
upload UI with new bank options and export instructions. Include booking
templates, improved AI categorization, and transaction review enhancements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:38:44 +01:00

2625 lines
83 KiB
TypeScript

import type {
TransactionCategory,
MappingResult,
VatJournalLine,
Transaction,
EntityType,
VatTreatment,
RiskLevel,
} from '@/types'
import { getVatRate, generateReverseChargeLines, generateInputVatLine } from './vat-entries'
// ============================================================
// Types
// ============================================================
export type TemplateGroup =
| 'premises'
| 'vehicle'
| 'it_software'
| 'office_supplies'
| 'marketing'
| 'travel'
| 'representation'
| 'insurance'
| 'professional_services'
| 'bank_finance'
| 'telecom'
| 'education'
| 'personnel'
| 'revenue'
| 'financial'
| 'private_transfers'
| 'equipment'
| 'subscriptions'
export interface BookingTemplate {
id: string
name_sv: string
name_en: string
group: TemplateGroup
direction: 'expense' | 'income' | 'transfer'
entity_applicability: 'all' | 'enskild_firma' | 'aktiebolag'
debit_account: string
credit_account: string
debit_account_ab?: string
credit_account_ab?: string
vat_treatment: VatTreatment | null
vat_rate: number
deductibility: 'full' | 'non_deductible' | 'conditional'
deductibility_note_sv?: string
special_rules_sv?: string
mcc_codes: number[]
keywords: string[]
risk_level: RiskLevel
requires_review: boolean
impact_score: number
auto_match_confidence: number
default_private: boolean
fallback_category: TransactionCategory
description_sv: string
}
export interface TemplateGroupInfo {
group: TemplateGroup
label_sv: string
label_en: string
templates: BookingTemplate[]
}
export interface TemplateMatch {
template: BookingTemplate
confidence: number
}
// ============================================================
// Template Group Labels
// ============================================================
const GROUP_LABELS: Record<TemplateGroup, { sv: string; en: string }> = {
premises: { sv: 'Lokalkostnader', en: 'Premises' },
vehicle: { sv: 'Fordon', en: 'Vehicle' },
it_software: { sv: 'IT & Programvara', en: 'IT & Software' },
office_supplies: { sv: 'Kontorsmaterial', en: 'Office Supplies' },
marketing: { sv: 'Marknadsföring', en: 'Marketing' },
travel: { sv: 'Resor & Transport', en: 'Travel & Transport' },
representation: { sv: 'Representation', en: 'Representation' },
insurance: { sv: 'Försäkringar', en: 'Insurance' },
professional_services: { sv: 'Professionella tjänster', en: 'Professional Services' },
bank_finance: { sv: 'Bank & Finans', en: 'Banking & Finance' },
telecom: { sv: 'Telekom & Internet', en: 'Telecom & Internet' },
education: { sv: 'Utbildning', en: 'Education' },
personnel: { sv: 'Personal', en: 'Personnel' },
revenue: { sv: 'Intäkter', en: 'Revenue' },
financial: { sv: 'Finansiella poster', en: 'Financial Items' },
private_transfers: { sv: 'Privata transaktioner', en: 'Private Transfers' },
equipment: { sv: 'Inventarier & Utrustning', en: 'Equipment' },
subscriptions: { sv: 'Prenumerationer & Medlemskap', en: 'Subscriptions & Memberships' },
}
// ============================================================
// Template Data (100 templates)
// ============================================================
export const BOOKING_TEMPLATES: readonly BookingTemplate[] = [
// --- PREMISES (1-8) ---
{
id: 'premises_rent',
name_sv: 'Lokalhyra',
name_en: 'Office rent',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5010',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Lokalhyra är momsfri om hyresvärden inte är frivilligt momsregistrerad',
mcc_codes: [],
keywords: ['hyra', 'lokal', 'kontor', 'rent', 'office space', 'kontorslokal'],
risk_level: 'NONE',
requires_review: false,
impact_score: 10,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Månadshyra för kontors- eller affärslokal',
},
{
id: 'premises_rent_vat',
name_sv: 'Lokalhyra (momsbelagd)',
name_en: 'Office rent (with VAT)',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5010',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
special_rules_sv: 'Gäller när hyresvärden är frivilligt momsregistrerad',
mcc_codes: [],
keywords: ['hyra', 'lokal', 'moms', 'kontorshyra'],
risk_level: 'NONE',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Lokalhyra med moms (frivilligt momsregistrerad hyresvärd)',
},
{
id: 'premises_electricity',
name_sv: 'El',
name_en: 'Electricity',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5020',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [4900],
keywords: ['el', 'electricity', 'vattenfall', 'eon', 'fortum', 'ellevio', 'kraftbolag', 'elnät'],
risk_level: 'NONE',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Elkostnad för kontors- eller affärslokal',
},
{
id: 'premises_heating',
name_sv: 'Uppvärmning',
name_en: 'Heating',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5030',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['värme', 'fjärrvärme', 'uppvärmning', 'heating'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Uppvärmningskostnad för lokal',
},
{
id: 'premises_water',
name_sv: 'Vatten & Avlopp',
name_en: 'Water & Sewage',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5040',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['vatten', 'avlopp', 'water', 'va-avgift'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Vatten- och avloppskostnader',
},
{
id: 'premises_cleaning',
name_sv: 'Städning',
name_en: 'Cleaning services',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5050',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7349],
keywords: ['städ', 'cleaning', 'rengöring', 'städfirma', 'lokalvård'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Städning av kontors- eller affärslokal',
},
{
id: 'premises_repairs',
name_sv: 'Reparation & Underhåll av lokal',
name_en: 'Premises repairs & maintenance',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5070',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [1520, 1711, 1731, 1740, 1750, 1761, 1771],
keywords: ['reparation', 'underhåll', 'renovering', 'repair', 'maintenance', 'lokal'],
risk_level: 'LOW',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Reparation och underhåll av kontors- eller affärslokal',
},
{
id: 'premises_security',
name_sv: 'Bevakning & Larm',
name_en: 'Security & Alarms',
group: 'premises',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5060',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7382],
keywords: ['securitas', 'larm', 'bevakning', 'security', 'alarm', 'verisure'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Bevakning, larm och säkerhetstjänster',
},
// --- VEHICLE (9-15) ---
{
id: 'vehicle_fuel',
name_sv: 'Drivmedel',
name_en: 'Fuel',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5611',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
special_rules_sv: 'Drivmedel till firmabil, ej privat körning',
mcc_codes: [5541, 5542, 5983],
keywords: ['bensin', 'diesel', 'drivmedel', 'fuel', 'tank', 'okq8', 'circle k', 'preem', 'st1', 'shell', 'ingo'],
risk_level: 'LOW',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Drivmedel (bensin/diesel) för tjänstefordon',
},
{
id: 'vehicle_leasing',
name_sv: 'Billeasing',
name_en: 'Car leasing',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5615',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Max 50% momsavdrag för personbil',
special_rules_sv: 'Personbil: halvt momsavdrag. Lastbil/lätt lastbil: fullt avdrag.',
mcc_codes: [7512, 7513],
keywords: ['leasing', 'billeasing', 'car lease', 'leasingavgift'],
risk_level: 'LOW',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Leasingavgift för tjänstefordon',
},
{
id: 'vehicle_insurance',
name_sv: 'Fordonsförsäkring',
name_en: 'Vehicle insurance',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5612',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Försäkringar är momsfria',
mcc_codes: [6300],
keywords: ['bilförsäkring', 'fordonsförsäkring', 'car insurance', 'vehicle insurance', 'if', 'trygg-hansa', 'folksam'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Försäkring för tjänstefordon',
},
{
id: 'vehicle_repairs',
name_sv: 'Reparation & Service fordon',
name_en: 'Vehicle repairs & service',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5613',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [5511, 5521, 5531, 5532, 5533, 7531, 7534, 7535, 7538, 7542],
keywords: ['bilverkstad', 'service', 'reparation', 'däck', 'mekonomen', 'autoexperten', 'bilprovning', 'besiktning'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Reparation, service och underhåll av fordon',
},
{
id: 'vehicle_parking',
name_sv: 'Parkering',
name_en: 'Parking',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5614',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7521, 7523],
keywords: ['parkering', 'parking', 'p-avgift', 'easypark', 'apcoa', 'q-park', 'aimo'],
risk_level: 'NONE',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Parkeringsavgift vid tjänsteärende',
},
{
id: 'vehicle_toll',
name_sv: 'Trängselskatt & Vägtull',
name_en: 'Congestion tax & Road tolls',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5616',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Trängselskatt är inte momsbelagd',
mcc_codes: [4784],
keywords: ['trängselskatt', 'vägtull', 'toll', 'brobizz', 'congestion'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Trängselskatt och vägtullar',
},
{
id: 'vehicle_ev_charging',
name_sv: 'Laddning elbil',
name_en: 'EV charging',
group: 'vehicle',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5611',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [5552],
keywords: ['laddning', 'elbil', 'charging', 'charge', 'tesla', 'ionity', 'recharge', 'mer'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Laddning av elbil för tjänstebruk',
},
// --- IT & SOFTWARE (16-25) ---
{
id: 'it_saas_subscription',
name_sv: 'Programvara / SaaS-prenumeration',
name_en: 'Software / SaaS subscription',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [5734, 5817, 5818],
keywords: ['software', 'saas', 'programvara', 'licens', 'subscription', 'app', 'microsoft', 'google', 'adobe', 'slack', 'notion', 'figma', 'github', 'atlassian', 'jira'],
risk_level: 'NONE',
requires_review: false,
impact_score: 10,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Programvarulicens eller SaaS-prenumeration',
},
{
id: 'it_saas_eu',
name_sv: 'Programvara / SaaS (EU, omvänd moms)',
name_en: 'Software / SaaS (EU, reverse charge)',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'EU-tjänst med omvänd skattskyldighet',
mcc_codes: [5734, 5817, 5818],
keywords: ['software', 'saas', 'eu', 'ireland', 'reverse charge', 'omvänd moms'],
risk_level: 'LOW',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Programvara från EU-land med omvänd skattskyldighet',
},
{
id: 'it_cloud_hosting',
name_sv: 'Molntjänster / Hosting',
name_en: 'Cloud services / Hosting',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5421',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Ofta EU/utländsk leverantör med omvänd skattskyldighet',
mcc_codes: [4816],
keywords: ['aws', 'azure', 'google cloud', 'gcp', 'hosting', 'server', 'cloud', 'vercel', 'heroku', 'digitalocean', 'cloudflare', 'hetzner'],
risk_level: 'NONE',
requires_review: false,
impact_score: 9,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Molnbaserade tjänster, webbhotell och serverhosting',
},
{
id: 'it_domain_name',
name_sv: 'Domännamn',
name_en: 'Domain name',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5421',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['domän', 'domain', 'dns', 'loopia', 'binero', 'godaddy', 'namecheap'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Registrering och förnyelse av domännamn',
},
{
id: 'it_hardware_small',
name_sv: 'IT-tillbehör (förbrukningsinventarie)',
name_en: 'IT accessories (consumable)',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5410',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
special_rules_sv: 'Under halva prisbasbeloppet = förbrukningsinventarie',
mcc_codes: [5045, 5065, 5732],
keywords: ['tangentbord', 'mus', 'headset', 'adapter', 'kabel', 'usb', 'monitor', 'skärm', 'dockningsstation', 'keyboard', 'mouse', 'webcam'],
risk_level: 'NONE',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_equipment',
description_sv: 'Mindre IT-tillbehör (under halva prisbasbeloppet)',
},
{
id: 'it_computer',
name_sv: 'Dator / Laptop',
name_en: 'Computer / Laptop',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5410',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
special_rules_sv: 'Över halva prisbasbeloppet = aktivering på konto 1250. Blandad användning → bara företagsdelen avdragsgill.',
mcc_codes: [5045, 5732],
keywords: ['dator', 'laptop', 'macbook', 'thinkpad', 'computer', 'pc', 'apple', 'dell', 'lenovo', 'hp'],
risk_level: 'LOW',
requires_review: true,
impact_score: 7,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_equipment',
description_sv: 'Dator eller laptop (granska om aktivering krävs)',
},
{
id: 'it_phone',
name_sv: 'Mobiltelefon',
name_en: 'Mobile phone',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5410',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Blandad användning: bara yrkesmässig del avdragsgill',
mcc_codes: [5065, 4812],
keywords: ['mobil', 'telefon', 'iphone', 'samsung', 'phone', 'mobiltelefon'],
risk_level: 'MEDIUM',
requires_review: true,
impact_score: 6,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_equipment',
description_sv: 'Mobiltelefon (granska yrkesmässig andel)',
},
{
id: 'it_ai_services',
name_sv: 'AI-tjänster',
name_en: 'AI services',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Ofta utländsk leverantör (USA) med omvänd skattskyldighet',
mcc_codes: [],
keywords: ['openai', 'chatgpt', 'anthropic', 'claude', 'ai', 'midjourney', 'copilot'],
risk_level: 'NONE',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'AI-plattformar och tjänster (ChatGPT, Claude, etc.)',
},
{
id: 'it_antivirus',
name_sv: 'Antivirus / Säkerhet',
name_en: 'Antivirus / Security',
group: 'it_software',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['antivirus', 'security', 'vpn', 'norton', 'kaspersky', '1password', 'lastpass', 'bitwarden'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Säkerhetsprogramvara och VPN-tjänster',
},
// --- OFFICE SUPPLIES (26-31) ---
{
id: 'office_supplies_general',
name_sv: 'Kontorsmaterial',
name_en: 'Office supplies',
group: 'office_supplies',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6110',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [5111, 5112, 5943, 5944],
keywords: ['kontorsmaterial', 'pennor', 'papper', 'office supplies', 'staples', 'kontorsvaror'],
risk_level: 'NONE',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Kontorsmaterial och förbrukningsvaror',
},
{
id: 'office_printing',
name_sv: 'Tryck & Kopiering',
name_en: 'Printing & Copying',
group: 'office_supplies',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6120',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [2741, 2791],
keywords: ['tryck', 'print', 'trycksaker', 'kopiering', 'visitkort', 'broschyr'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Trycksaker, kopior och kontorsutskrifter',
},
{
id: 'office_postage',
name_sv: 'Porto & Frakt',
name_en: 'Postage & Shipping',
group: 'office_supplies',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6250',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Posttjänster är momsfria, frakttjänster kan ha moms',
mcc_codes: [4215, 4211],
keywords: ['porto', 'postnord', 'frakt', 'shipping', 'dhl', 'ups', 'fedex', 'bring', 'paket'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Porto och fraktkostnader',
},
{
id: 'office_postage_vat',
name_sv: 'Frakt (momsbelagd)',
name_en: 'Shipping (with VAT)',
group: 'office_supplies',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6250',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [4215],
keywords: ['frakt', 'shipping', 'dhl', 'ups', 'schenker', 'transport'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Frakttjänster med moms',
},
{
id: 'office_furniture_small',
name_sv: 'Kontorsmöbler (förbrukningsinventarie)',
name_en: 'Office furniture (consumable)',
group: 'office_supplies',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5410',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [5712, 5021],
keywords: ['möbler', 'stol', 'skrivbord', 'ikea', 'furniture', 'kontorsstol', 'hyllor'],
risk_level: 'LOW',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_equipment',
description_sv: 'Kontorsmöbler under halva prisbasbeloppet',
},
{
id: 'office_books_lit',
name_sv: 'Facklitteratur',
name_en: 'Professional literature',
group: 'office_supplies',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6970',
credit_account: '1930',
vat_treatment: 'reduced_6',
vat_rate: 0.06,
deductibility: 'full',
special_rules_sv: 'Böcker har reducerad moms 6%',
mcc_codes: [5192, 5942],
keywords: ['bok', 'böcker', 'book', 'facklitteratur', 'adlibris', 'bokus', 'amazon'],
risk_level: 'LOW',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_education',
description_sv: 'Yrkesrelaterad facklitteratur (6% moms)',
},
// --- MARKETING (32-38) ---
{
id: 'marketing_online_ads',
name_sv: 'Digital annonsering',
name_en: 'Online advertising',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5910',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Google/Meta fakturerar ofta från Irland → omvänd skattskyldighet',
mcc_codes: [7311],
keywords: ['google ads', 'facebook ads', 'meta ads', 'instagram ads', 'linkedin ads', 'annons', 'advertising', 'adwords', 'kampanj'],
risk_level: 'NONE',
requires_review: false,
impact_score: 9,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Digital annonsering (Google, Meta, LinkedIn etc.)',
},
{
id: 'marketing_print_ads',
name_sv: 'Tryckt annonsering',
name_en: 'Print advertising',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5910',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['annons', 'tidning', 'press', 'print ad', 'reklam'],
risk_level: 'NONE',
requires_review: false,
impact_score: 3,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Annonsering i tidningar och trycksaker',
},
{
id: 'marketing_design',
name_sv: 'Grafisk design / Webbdesign',
name_en: 'Graphic / Web design',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5920',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7333],
keywords: ['design', 'grafisk', 'logotyp', 'webb', 'website', 'logo', 'branding', 'grafiker'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Grafisk design, logotyper och webbdesign',
},
{
id: 'marketing_promotional',
name_sv: 'Reklamgåvor & Profilmaterial',
name_en: 'Promotional items',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5930',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Max 300 kr/mottagare exkl moms för reklamgåvor',
mcc_codes: [],
keywords: ['reklamgåva', 'profilmaterial', 'promotional', 'giveaway', 'tröjor', 'pennor'],
risk_level: 'MEDIUM',
requires_review: true,
impact_score: 3,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Reklamgåvor och profilprodukter (max 300 kr/mottagare)',
},
{
id: 'marketing_seo_sem',
name_sv: 'SEO / SEM-tjänster',
name_en: 'SEO / SEM services',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5910',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['seo', 'sem', 'sökmotoroptimering', 'search engine'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Sökmotoroptimering och sökmarknadsföring',
},
{
id: 'marketing_social_media_tools',
name_sv: 'Verktyg för sociala medier',
name_en: 'Social media tools',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5920',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['hootsuite', 'buffer', 'later', 'canva', 'social media', 'sociala medier'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Verktyg för hantering av sociala medier',
},
{
id: 'marketing_photography',
name_sv: 'Fotografering / Videoproduktion',
name_en: 'Photography / Video production',
group: 'marketing',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5920',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7332, 7829],
keywords: ['foto', 'fotograf', 'video', 'film', 'photography', 'videoproduktion'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Professionell fotografering och videoproduktion',
},
// --- TRAVEL (39-46) ---
{
id: 'travel_domestic_flight',
name_sv: 'Inrikesflyg',
name_en: 'Domestic flight',
group: 'travel',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5810',
credit_account: '1930',
vat_treatment: 'reduced_6',
vat_rate: 0.06,
deductibility: 'full',
special_rules_sv: 'Inrikesflyg har 6% moms',
mcc_codes: [3000, 3001, 3002, 3003, 4511],
keywords: ['flyg', 'sas', 'norwegian', 'bra', 'flight', 'boarding', 'flygbiljett'],
risk_level: 'LOW',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Inrikesflyg i tjänsten (6% moms)',
},
{
id: 'travel_international_flight',
name_sv: 'Utrikesflyg',
name_en: 'International flight',
group: 'travel',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5810',
credit_account: '1930',
vat_treatment: 'export',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Utrikesflyg är momsfritt',
mcc_codes: [3000, 3001, 3002, 3003, 4511],
keywords: ['flyg', 'flight', 'international', 'utrikes', 'airport'],
risk_level: 'LOW',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Utrikesflyg i tjänsten (momsfritt)',
},
{
id: 'travel_train',
name_sv: 'Tåg & Kollektivtrafik',
name_en: 'Train & Public transport',
group: 'travel',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5810',
credit_account: '1930',
vat_treatment: 'reduced_6',
vat_rate: 0.06,
deductibility: 'full',
special_rules_sv: 'Persontransport har 6% moms',
mcc_codes: [4011, 4111, 4112, 4131],
keywords: ['sj', 'tåg', 'train', 'sl', 'västtrafik', 'skånetrafiken', 'kollektivtrafik', 'pendeltåg', 'tunnelbana'],
risk_level: 'NONE',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Tåg och kollektivtrafik i tjänsten (6% moms)',
},
{
id: 'travel_taxi',
name_sv: 'Taxi',
name_en: 'Taxi',
group: 'travel',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5810',
credit_account: '1930',
vat_treatment: 'reduced_6',
vat_rate: 0.06,
deductibility: 'full',
mcc_codes: [4121],
keywords: ['taxi', 'uber', 'bolt', 'cab', 'taxikurir', 'taxi stockholm', 'sverigetaxi'],
risk_level: 'LOW',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Taxi i tjänsten (6% moms)',
},
{
id: 'travel_hotel',
name_sv: 'Hotell',
name_en: 'Hotel',
group: 'travel',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5820',
credit_account: '1930',
vat_treatment: 'reduced_12',
vat_rate: 0.12,
deductibility: 'full',
special_rules_sv: 'Logi har 12% moms. Frukost särredovisas med 12% moms.',
mcc_codes: [3501, 3502, 3503, 3504, 7011],
keywords: ['hotell', 'hotel', 'logi', 'övernattning', 'scandic', 'elite', 'best western', 'booking', 'airbnb'],
risk_level: 'LOW',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Hotellövernattning i tjänsten (12% moms)',
},
{
id: 'travel_mileage',
name_sv: 'Milersättning',
name_en: 'Mileage allowance',
group: 'travel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '5811',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Skattefritt 25 kr/mil (2024). Gäller egen bil i tjänsten.',
mcc_codes: [],
keywords: ['milersättning', 'mileage', 'körjournal', 'bilersättning'],
risk_level: 'LOW',
requires_review: true,
impact_score: 5,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Milersättning vid användning av egen bil i tjänsten',
},
{
id: 'travel_per_diem',
name_sv: 'Traktamente',
name_en: 'Per diem',
group: 'travel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '5830',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Skattefritt traktamente vid tjänsteresa med övernattning',
mcc_codes: [],
keywords: ['traktamente', 'per diem', 'dagtraktamente'],
risk_level: 'LOW',
requires_review: true,
impact_score: 4,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Traktamente vid tjänsteresa med övernattning',
},
{
id: 'travel_rental_car',
name_sv: 'Hyrbil',
name_en: 'Rental car',
group: 'travel',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5810',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7512],
keywords: ['hyrbil', 'rental car', 'europcar', 'hertz', 'avis', 'sixt'],
risk_level: 'LOW',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_travel',
description_sv: 'Hyrbil i tjänsten',
},
// --- REPRESENTATION (47-50) ---
{
id: 'representation_external',
name_sv: 'Extern representation (måltid)',
name_en: 'External representation (meal)',
group: 'representation',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6071',
credit_account: '1930',
vat_treatment: 'reduced_12',
vat_rate: 0.12,
deductibility: 'conditional',
deductibility_note_sv: 'Max 300 kr/person exkl moms (IL 16 kap 2§)',
special_rules_sv: 'Dokumentera: syfte, deltagare, företag. Momsavdrag max 300 kr/person.',
mcc_codes: [5812, 5813, 5814],
keywords: ['representation', 'lunch', 'middag', 'restaurang', 'restaurant', 'kund', 'kundmöte'],
risk_level: 'HIGH',
requires_review: true,
impact_score: 7,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Representation med kund/affärspartner (dokumentera noggrant)',
},
{
id: 'representation_internal',
name_sv: 'Intern representation (personalaktivitet)',
name_en: 'Internal representation (staff event)',
group: 'representation',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '6072',
credit_account: '1930',
vat_treatment: 'reduced_12',
vat_rate: 0.12,
deductibility: 'conditional',
deductibility_note_sv: 'Max 300 kr/person exkl moms',
special_rules_sv: 'Gäller personalfester, kick-offs etc. Max 2 tillfällen/år för fullt avdrag.',
mcc_codes: [],
keywords: ['personalfest', 'kick-off', 'teambuilding', 'julbord', 'sommarfest'],
risk_level: 'MEDIUM',
requires_review: true,
impact_score: 3,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Intern representation för personal',
},
{
id: 'representation_gift',
name_sv: 'Representationsgåva',
name_en: 'Business gift',
group: 'representation',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6071',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Max 180 kr/mottagare för representationsgåvor',
mcc_codes: [],
keywords: ['gåva', 'present', 'gift', 'representationsgåva'],
risk_level: 'HIGH',
requires_review: true,
impact_score: 2,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Gåva till kund/affärspartner (max 180 kr/mottagare)',
},
{
id: 'representation_conference',
name_sv: 'Konferens & Mässa',
name_en: 'Conference & Trade show',
group: 'representation',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5990',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7941, 7922],
keywords: ['konferens', 'mässa', 'conference', 'trade show', 'event', 'utställning', 'biljett'],
risk_level: 'LOW',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_education',
description_sv: 'Avgifter för konferenser och mässor',
},
// --- INSURANCE (51-54) ---
{
id: 'insurance_business',
name_sv: 'Företagsförsäkring',
name_en: 'Business insurance',
group: 'insurance',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6310',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Försäkringspremier är momsfria',
mcc_codes: [6300],
keywords: ['försäkring', 'insurance', 'företagsförsäkring', 'ansvarsförsäkring', 'if', 'trygg-hansa', 'länsförsäkringar'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Företagsförsäkring (egendoms-, ansvars- eller avbrottsförsäkring)',
},
{
id: 'insurance_liability',
name_sv: 'Ansvarsförsäkring / Konsultförsäkring',
name_en: 'Liability / Professional insurance',
group: 'insurance',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6310',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['ansvarsförsäkring', 'konsultförsäkring', 'liability', 'professional insurance'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Yrkes- eller ansvarsförsäkring',
},
{
id: 'insurance_pension_ef',
name_sv: 'Pensionsförsäkring (EF)',
name_en: 'Pension insurance (EF)',
group: 'insurance',
direction: 'expense',
entity_applicability: 'enskild_firma',
debit_account: '6530',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'conditional',
deductibility_note_sv: 'Avdragsgill i NE-deklarationen, inte i bokföringen direkt',
special_rules_sv: 'EF: Pensionssparande dras av i NE-blanketten, inte som kostnad i rörelsen.',
mcc_codes: [],
keywords: ['pension', 'pensionsförsäkring', 'itp', 'avanza pension', 'spp'],
risk_level: 'MEDIUM',
requires_review: true,
impact_score: 4,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Pensionssparande för enskild firma (granska avdragsregel)',
},
{
id: 'insurance_pension_ab',
name_sv: 'Pensionsförsäkring (AB)',
name_en: 'Pension insurance (AB)',
group: 'insurance',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '7410',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'AB: Pensionskostnad är en avdragsgill personalkostnad',
mcc_codes: [],
keywords: ['pension', 'pensionsförsäkring', 'itp', 'tjänstepension'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Tjänstepension för anställda i aktiebolag',
},
// --- PROFESSIONAL SERVICES (55-60) ---
{
id: 'prof_accounting',
name_sv: 'Redovisningstjänster',
name_en: 'Accounting services',
group: 'professional_services',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6530',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [8931],
keywords: ['redovisning', 'bokföring', 'revisor', 'accounting', 'bokföringstjänst', 'redovisningsbyrå'],
risk_level: 'NONE',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_professional_services',
description_sv: 'Redovisning, bokföring och revisionstjänster',
},
{
id: 'prof_legal',
name_sv: 'Juridiska tjänster',
name_en: 'Legal services',
group: 'professional_services',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6530',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [8111],
keywords: ['advokat', 'juridisk', 'legal', 'lawyer', 'jurist', 'avtal', 'kontrakt'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_professional_services',
description_sv: 'Advokattjänster och juridisk rådgivning',
},
{
id: 'prof_consulting',
name_sv: 'Konsulttjänster',
name_en: 'Consulting services',
group: 'professional_services',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6550',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7392],
keywords: ['konsult', 'consulting', 'rådgivning', 'advisory', 'management'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_professional_services',
description_sv: 'Konsultarvoden och rådgivningstjänster',
},
{
id: 'prof_bolagsverket',
name_sv: 'Bolagsverket-avgifter',
name_en: 'Companies Registration Office fees',
group: 'professional_services',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6990',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Myndighetsavgifter är inte momspliktiga',
mcc_codes: [],
keywords: ['bolagsverket', 'registrering', 'årsredovisning', 'companies registration'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Avgifter till Bolagsverket (registrering, årsredovisning etc.)',
},
{
id: 'prof_patent',
name_sv: 'Patent & Varumärken',
name_en: 'Patents & Trademarks',
group: 'professional_services',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6990',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['patent', 'varumärke', 'trademark', 'prv', 'immaterialrätt'],
risk_level: 'NONE',
requires_review: false,
impact_score: 2,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Patent- och varumärkesregistrering',
},
{
id: 'prof_recruitment',
name_sv: 'Rekryteringstjänster',
name_en: 'Recruitment services',
group: 'professional_services',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '6540',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [7361],
keywords: ['rekrytering', 'recruitment', 'headhunting', 'personalförmedling'],
risk_level: 'NONE',
requires_review: false,
impact_score: 3,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_professional_services',
description_sv: 'Rekrytering och personalförmedlingstjänster',
},
// --- BANK & FINANCE (61-66) ---
{
id: 'bank_fees',
name_sv: 'Bankavgifter',
name_en: 'Bank fees',
group: 'bank_finance',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6570',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Banktjänster är momsfria',
mcc_codes: [6010, 6011, 6012],
keywords: ['bankavgift', 'bank fee', 'kontoavgift', 'årsavgift', 'månadsavgift'],
risk_level: 'NONE',
requires_review: false,
impact_score: 9,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_bank_fees',
description_sv: 'Bankavgifter och kontoavgifter',
},
{
id: 'bank_card_fees',
name_sv: 'Kortavgifter / Betalterminal',
name_en: 'Card fees / Payment terminal',
group: 'bank_finance',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6570',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['kortavgift', 'zettle', 'izettle', 'stripe', 'klarna', 'swish', 'betalterminal', 'card fee', 'nets'],
risk_level: 'NONE',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_card_fees',
description_sv: 'Kortavgifter och betalterminalavgifter',
},
{
id: 'bank_interest_income',
name_sv: 'Ränteintäkt',
name_en: 'Interest income',
group: 'bank_finance',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '8310',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['ränta', 'ränteinkomst', 'interest income', 'sparränta'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'income_other',
description_sv: 'Ränteintäkter på bankkonto eller placeringar',
},
{
id: 'bank_interest_expense',
name_sv: 'Räntekostnad',
name_en: 'Interest expense',
group: 'bank_finance',
direction: 'expense',
entity_applicability: 'all',
debit_account: '8410',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['ränta', 'räntekostnad', 'interest expense', 'låneränta'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Räntekostnad på lån eller kredit',
},
{
id: 'bank_currency_loss',
name_sv: 'Valutakursförlust',
name_en: 'Currency exchange loss',
group: 'bank_finance',
direction: 'expense',
entity_applicability: 'all',
debit_account: '7960',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [6051],
keywords: ['valuta', 'currency', 'växling', 'kursförlust', 'exchange'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_currency_exchange',
description_sv: 'Valutakursförluster vid betalning i utländsk valuta',
},
{
id: 'bank_currency_gain',
name_sv: 'Valutakursvinst',
name_en: 'Currency exchange gain',
group: 'bank_finance',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3960',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['valuta', 'currency', 'kursvinst', 'exchange gain'],
risk_level: 'NONE',
requires_review: false,
impact_score: 3,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'income_other',
description_sv: 'Valutakursvinster vid betalning i utländsk valuta',
},
// --- TELECOM (67-70) ---
{
id: 'telecom_mobile',
name_sv: 'Mobilabonnemang',
name_en: 'Mobile subscription',
group: 'telecom',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6211',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Blandad användning: bara yrkesmässig del avdragsgill',
mcc_codes: [4812, 4814],
keywords: ['mobil', 'tele2', 'telia', 'tre', 'telenor', 'hallon', 'comviq', 'mobilabonnemang', 'telefon'],
risk_level: 'LOW',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Mobilabonnemang (granska yrkesmässig andel)',
},
{
id: 'telecom_internet',
name_sv: 'Internetanslutning',
name_en: 'Internet connection',
group: 'telecom',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6230',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [4816],
keywords: ['internet', 'bredband', 'fiber', 'broadband', 'bahnhof', 'telia', 'comhem'],
risk_level: 'NONE',
requires_review: false,
impact_score: 7,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Internetanslutning för kontor',
},
{
id: 'telecom_landline',
name_sv: 'Fast telefoni',
name_en: 'Landline phone',
group: 'telecom',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6212',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [4813],
keywords: ['fast telefon', 'landline', 'växel', 'ip-telefoni', 'voip'],
risk_level: 'NONE',
requires_review: false,
impact_score: 3,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Fast telefoni och IP-telefoni',
},
{
id: 'telecom_coworking',
name_sv: 'Coworking / Kontorshotell',
name_en: 'Coworking space',
group: 'telecom',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5010',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['coworking', 'kontorshotell', 'wework', 'norrsken', 'epicenter', 'united spaces', 'regus'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_office',
description_sv: 'Coworking-plats eller kontorshotell',
},
// --- EDUCATION (71-73) ---
{
id: 'education_course',
name_sv: 'Kurs / Utbildning',
name_en: 'Course / Training',
group: 'education',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6991',
credit_account: '1930',
debit_account_ab: '7610',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Utbildningstjänster är momsfria. AB: konto 7610, EF: konto 6991.',
mcc_codes: [8220, 8241, 8244, 8249, 8299],
keywords: ['kurs', 'utbildning', 'course', 'training', 'workshop', 'certifiering', 'certification'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_education',
description_sv: 'Yrkesrelaterade kurser och utbildningar',
},
{
id: 'education_online_course',
name_sv: 'Onlinekurs (EU/utländsk)',
name_en: 'Online course (EU/foreign)',
group: 'education',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6991',
credit_account: '1930',
debit_account_ab: '7610',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Utländska onlinekurser kan vara tjänst med omvänd skattskyldighet',
mcc_codes: [5815, 5816],
keywords: ['udemy', 'coursera', 'pluralsight', 'linkedin learning', 'skillshare', 'online course'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_education',
description_sv: 'Onlinekurser från utländska plattformar',
},
{
id: 'education_membership',
name_sv: 'Branschförening / Medlemskap',
name_en: 'Trade association / Membership',
group: 'education',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6980',
credit_account: '1930',
vat_treatment: 'exempt',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Föreningsavgifter är normalt momsfria',
mcc_codes: [8641, 8651, 8661, 8699],
keywords: ['medlemskap', 'membership', 'förening', 'branschorganisation', 'förbund', 'svenskt näringsliv', 'företagarna'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_education',
description_sv: 'Medlemsavgift i branschorganisation eller yrkesförening',
},
// --- PERSONNEL (74-78) ---
{
id: 'personnel_salary',
name_sv: 'Lön (netto)',
name_en: 'Salary (net)',
group: 'personnel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '7210',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['lön', 'salary', 'nettolön', 'löneutbetalning'],
risk_level: 'NONE',
requires_review: true,
impact_score: 8,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Nettolön till anställd',
},
{
id: 'personnel_employer_tax',
name_sv: 'Arbetsgivaravgifter',
name_en: 'Employer social contributions',
group: 'personnel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '7510',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['arbetsgivaravgift', 'sociala avgifter', 'employer tax', 'skattekonto'],
risk_level: 'NONE',
requires_review: true,
impact_score: 7,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Arbetsgivaravgifter (31.42%)',
},
{
id: 'personnel_preliminary_tax',
name_sv: 'Preliminärskatt (AB)',
name_en: 'Preliminary tax (AB)',
group: 'personnel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '2510',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['preliminärskatt', 'skatt', 'tax', 'skatteverket', 'skattekonto'],
risk_level: 'NONE',
requires_review: true,
impact_score: 7,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Preliminärskatt till Skatteverket',
},
{
id: 'personnel_friskvard',
name_sv: 'Friskvårdsbidrag',
name_en: 'Wellness benefit',
group: 'personnel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '7690',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'conditional',
deductibility_note_sv: 'Skattefritt max 5 000 kr/anställd/år (2024)',
special_rules_sv: 'Friskvård är momsfri. Max 5 000 kr/år per anställd för skattefrihet.',
mcc_codes: [7941, 7991, 7992, 7997],
keywords: ['friskvård', 'gym', 'träning', 'wellness', 'friskvårdsbidrag'],
risk_level: 'MEDIUM',
requires_review: true,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Friskvårdsbidrag till anställd (max 5 000 kr/år)',
},
{
id: 'personnel_staff_food',
name_sv: 'Personalmat / Fika',
name_en: 'Staff meals / Coffee',
group: 'personnel',
direction: 'expense',
entity_applicability: 'aktiebolag',
debit_account: '7690',
credit_account: '1930',
vat_treatment: 'reduced_12',
vat_rate: 0.12,
deductibility: 'conditional',
deductibility_note_sv: 'Enklare förtäring (kaffe, frukt) avdragsgillt utan beloppsgräns. Mat = förmånsbeskattning.',
mcc_codes: [5812, 5814],
keywords: ['fika', 'kaffe', 'frukt', 'personalmat', 'staff food'],
risk_level: 'LOW',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Enklare förtäring för personal (kaffe, frukt etc.)',
},
// --- REVENUE (79-85) ---
{
id: 'revenue_services_25',
name_sv: 'Tjänsteförsäljning 25% moms',
name_en: 'Service revenue 25% VAT',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3001',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['konsult', 'tjänst', 'service', 'arvode', 'fee', 'faktura'],
risk_level: 'NONE',
requires_review: false,
impact_score: 10,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'income_services',
description_sv: 'Intäkter från tjänsteförsäljning med 25% moms',
},
{
id: 'revenue_products_25',
name_sv: 'Varuförsäljning 25% moms',
name_en: 'Product revenue 25% VAT',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3001',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['försäljning', 'vara', 'produkt', 'product', 'sale'],
risk_level: 'NONE',
requires_review: false,
impact_score: 9,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'income_products',
description_sv: 'Intäkter från varuförsäljning med 25% moms',
},
{
id: 'revenue_products_12',
name_sv: 'Varuförsäljning 12% moms (livsmedel)',
name_en: 'Product revenue 12% VAT (food)',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3002',
vat_treatment: 'reduced_12',
vat_rate: 0.12,
deductibility: 'full',
mcc_codes: [],
keywords: ['livsmedel', 'mat', 'food', 'restaurang'],
risk_level: 'NONE',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'income_products',
description_sv: 'Intäkter från livsmedelsförsäljning med 12% moms',
},
{
id: 'revenue_products_6',
name_sv: 'Försäljning 6% moms (kultur/böcker)',
name_en: 'Revenue 6% VAT (culture/books)',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3003',
vat_treatment: 'reduced_6',
vat_rate: 0.06,
deductibility: 'full',
mcc_codes: [],
keywords: ['kultur', 'bok', 'tidning', 'evenemang', 'culture', 'book'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'income_products',
description_sv: 'Intäkter med 6% moms (böcker, kultur, evenemang)',
},
{
id: 'revenue_eu_services',
name_sv: 'Tjänsteförsäljning EU (omvänd moms)',
name_en: 'Service revenue EU (reverse charge)',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3308',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Tjänsteförsäljning till EU-företag → omvänd skattskyldighet, rapportera i ruta 39',
mcc_codes: [],
keywords: ['eu', 'export', 'eu service', 'reverse charge', 'utlandsförsäljning'],
risk_level: 'LOW',
requires_review: false,
impact_score: 6,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'income_services',
description_sv: 'Tjänsteförsäljning till EU-företag (momsfritt, ruta 39)',
},
{
id: 'revenue_export',
name_sv: 'Export utanför EU',
name_en: 'Export outside EU',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3305',
vat_treatment: 'export',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Export utanför EU → momsfritt, rapportera i ruta 40',
mcc_codes: [],
keywords: ['export', 'utland', 'usa', 'utanför eu', 'non-eu'],
risk_level: 'LOW',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'income_services',
description_sv: 'Export av varor/tjänster utanför EU (momsfritt, ruta 40)',
},
{
id: 'revenue_other',
name_sv: 'Övrig intäkt',
name_en: 'Other revenue',
group: 'revenue',
direction: 'income',
entity_applicability: 'all',
debit_account: '1930',
credit_account: '3900',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['övrigt', 'miscellaneous', 'other income', 'övrig intäkt'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'income_other',
description_sv: 'Övriga rörelseintäkter',
},
// --- FINANCIAL (86-88) ---
{
id: 'financial_loan_repayment',
name_sv: 'Amortering lån',
name_en: 'Loan repayment',
group: 'financial',
direction: 'transfer',
entity_applicability: 'all',
debit_account: '2350',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['amortering', 'lån', 'loan', 'repayment', 'avbetalning'],
risk_level: 'NONE',
requires_review: true,
impact_score: 5,
auto_match_confidence: 0.75,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Amortering av banklån',
},
{
id: 'financial_tax_account',
name_sv: 'Insättning skattekonto',
name_en: 'Tax account deposit',
group: 'financial',
direction: 'transfer',
entity_applicability: 'all',
debit_account: '1630',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['skattekonto', 'skatteverket', 'tax account', 'f-skatt', 'moms inbetalning'],
risk_level: 'NONE',
requires_review: true,
impact_score: 8,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Insättning på skattekonto hos Skatteverket',
},
{
id: 'financial_savings_transfer',
name_sv: 'Överföring till sparkonto',
name_en: 'Transfer to savings account',
group: 'financial',
direction: 'transfer',
entity_applicability: 'all',
debit_account: '1940',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['sparkonto', 'savings', 'överföring', 'transfer'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Överföring mellan företagets bankkonton',
},
// --- PRIVATE TRANSFERS (89-92) ---
{
id: 'private_withdrawal_ef',
name_sv: 'Eget uttag (EF)',
name_en: 'Owner withdrawal (EF)',
group: 'private_transfers',
direction: 'transfer',
entity_applicability: 'enskild_firma',
debit_account: '2013',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'non_deductible',
mcc_codes: [],
keywords: ['eget uttag', 'privat', 'withdrawal', 'egen insättning'],
risk_level: 'NONE',
requires_review: false,
impact_score: 10,
auto_match_confidence: 0.85,
default_private: true,
fallback_category: 'private',
description_sv: 'Privat uttag från företagskonto (enskild firma)',
},
{
id: 'private_deposit_ef',
name_sv: 'Egen insättning (EF)',
name_en: 'Owner deposit (EF)',
group: 'private_transfers',
direction: 'transfer',
entity_applicability: 'enskild_firma',
debit_account: '1930',
credit_account: '2018',
vat_treatment: null,
vat_rate: 0,
deductibility: 'non_deductible',
mcc_codes: [],
keywords: ['egen insättning', 'insättning', 'deposit', 'tillskott'],
risk_level: 'NONE',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.80,
default_private: true,
fallback_category: 'private',
description_sv: 'Egen insättning till företagskonto (enskild firma)',
},
{
id: 'private_shareholder_loan',
name_sv: 'Skuld till aktieägare (AB)',
name_en: 'Shareholder loan (AB)',
group: 'private_transfers',
direction: 'transfer',
entity_applicability: 'aktiebolag',
debit_account: '2893',
credit_account: '1930',
vat_treatment: null,
vat_rate: 0,
deductibility: 'non_deductible',
mcc_codes: [],
keywords: ['aktieägare', 'lån', 'shareholder', 'skuld till ägare'],
risk_level: 'LOW',
requires_review: true,
impact_score: 6,
auto_match_confidence: 0.75,
default_private: true,
fallback_category: 'private',
description_sv: 'Utbetalning bokförd som skuld till aktieägare',
},
{
id: 'private_expense',
name_sv: 'Privat kostnad',
name_en: 'Private expense',
group: 'private_transfers',
direction: 'expense',
entity_applicability: 'all',
debit_account: '2013',
credit_account: '1930',
debit_account_ab: '2893',
vat_treatment: null,
vat_rate: 0,
deductibility: 'non_deductible',
mcc_codes: [],
keywords: ['privat', 'private', 'personlig', 'personal'],
risk_level: 'NONE',
requires_review: false,
impact_score: 9,
auto_match_confidence: 0.85,
default_private: true,
fallback_category: 'private',
description_sv: 'Privat kostnad betald från företagskonto',
},
// --- EQUIPMENT (93-95) ---
{
id: 'equipment_tools',
name_sv: 'Verktyg & Maskiner (förbrukning)',
name_en: 'Tools & Machinery (consumable)',
group: 'equipment',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5410',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [5200, 5251, 5261, 5072],
keywords: ['verktyg', 'maskin', 'tool', 'machine', 'biltema', 'jula', 'bauhaus', 'hornbach'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.80,
default_private: false,
fallback_category: 'expense_equipment',
description_sv: 'Verktyg och maskiner under halva prisbasbeloppet',
},
{
id: 'equipment_capital',
name_sv: 'Inventarie (aktivering)',
name_en: 'Capital equipment (capitalize)',
group: 'equipment',
direction: 'expense',
entity_applicability: 'all',
debit_account: '1250',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
special_rules_sv: 'Över halva prisbasbeloppet: aktivera och skriv av. Avskrivning konto 7832.',
mcc_codes: [],
keywords: ['inventarie', 'anläggningstillgång', 'capital', 'aktivering', 'avskrivning'],
risk_level: 'LOW',
requires_review: true,
impact_score: 4,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_equipment',
description_sv: 'Inventarie som ska aktiveras och skrivas av',
},
{
id: 'equipment_work_clothes',
name_sv: 'Arbetskläder / Skyddsutrustning',
name_en: 'Work clothes / Safety equipment',
group: 'equipment',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5480',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Normala kläder ej avdragsgilla. Skyddskläder/uniformer med logotyp OK.',
special_rules_sv: 'Vardagskläder ej avdragsgilla (RÅ 1988 ref. 35). Skyddskläder och arbetskläder med tydlig företagsprofil OK.',
mcc_codes: [5651, 5691, 5699],
keywords: ['arbetskläder', 'skyddsutrustning', 'uniform', 'safety', 'skyddsskor'],
risk_level: 'HIGH',
requires_review: true,
impact_score: 4,
auto_match_confidence: 0.70,
default_private: false,
fallback_category: 'expense_other',
description_sv: 'Arbetskläder och skyddsutrustning (ej vardagskläder)',
},
// --- SUBSCRIPTIONS (96-100) ---
{
id: 'subscription_accounting_software',
name_sv: 'Bokföringsprogram',
name_en: 'Accounting software',
group: 'subscriptions',
direction: 'expense',
entity_applicability: 'all',
debit_account: '6530',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'full',
mcc_codes: [],
keywords: ['bokföring', 'fortnox', 'visma', 'bokio', 'dooer', 'accounting software'],
risk_level: 'NONE',
requires_review: false,
impact_score: 8,
auto_match_confidence: 0.90,
default_private: false,
fallback_category: 'expense_professional_services',
description_sv: 'Prenumeration på bokföringsprogramvara',
},
{
id: 'subscription_project_tools',
name_sv: 'Projektverktyg',
name_en: 'Project management tools',
group: 'subscriptions',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Ofta utländsk leverantör med omvänd skattskyldighet',
mcc_codes: [],
keywords: ['asana', 'monday', 'trello', 'basecamp', 'clickup', 'linear', 'project management'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Projekthanteringsverktyg',
},
{
id: 'subscription_email_marketing',
name_sv: 'E-postmarknadsföring',
name_en: 'Email marketing',
group: 'subscriptions',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5920',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
mcc_codes: [],
keywords: ['mailchimp', 'sendgrid', 'mailgun', 'brevo', 'email marketing', 'nyhetsbrev', 'newsletter'],
risk_level: 'NONE',
requires_review: false,
impact_score: 4,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_marketing',
description_sv: 'Verktyg för e-postmarknadsföring och nyhetsbrev',
},
{
id: 'subscription_music_streaming',
name_sv: 'Musik-/Mediestreaming (företag)',
name_en: 'Music/Media streaming (business)',
group: 'subscriptions',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'standard_25',
vat_rate: 0.25,
deductibility: 'conditional',
deductibility_note_sv: 'Avdragsgillt bara om det används yrkesmässigt (t.ex. bakgrundsmusik i butik)',
mcc_codes: [5815, 4899],
keywords: ['spotify', 'apple music', 'streaming', 'musik'],
risk_level: 'MEDIUM',
requires_review: true,
impact_score: 3,
auto_match_confidence: 0.70,
default_private: true,
fallback_category: 'expense_other',
description_sv: 'Musikstreaming (ofta privat, granska yrkesmässig användning)',
},
{
id: 'subscription_crm',
name_sv: 'CRM-system',
name_en: 'CRM system',
group: 'subscriptions',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Ofta utländsk leverantör med omvänd skattskyldighet',
mcc_codes: [],
keywords: ['hubspot', 'salesforce', 'pipedrive', 'crm', 'kundhantering'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'CRM-system för kundhantering',
},
{
id: 'subscription_storage',
name_sv: 'Molnlagring',
name_en: 'Cloud storage',
group: 'subscriptions',
direction: 'expense',
entity_applicability: 'all',
debit_account: '5420',
credit_account: '1930',
vat_treatment: 'reverse_charge',
vat_rate: 0,
deductibility: 'full',
special_rules_sv: 'Ofta utländsk leverantör med omvänd skattskyldighet',
mcc_codes: [],
keywords: ['dropbox', 'google drive', 'onedrive', 'icloud', 'storage', 'lagring', 'backup'],
risk_level: 'NONE',
requires_review: false,
impact_score: 5,
auto_match_confidence: 0.85,
default_private: false,
fallback_category: 'expense_software',
description_sv: 'Molnlagring och backup-tjänster',
},
]
// ============================================================
// Lookup Indexes (built once at module load)
// ============================================================
const templateById = new Map<string, BookingTemplate>()
const templatesByGroup = new Map<TemplateGroup, BookingTemplate[]>()
const templatesByMcc = new Map<number, BookingTemplate[]>()
for (const t of BOOKING_TEMPLATES) {
templateById.set(t.id, t)
const groupList = templatesByGroup.get(t.group) || []
groupList.push(t)
templatesByGroup.set(t.group, groupList)
for (const mcc of t.mcc_codes) {
const mccList = templatesByMcc.get(mcc) || []
mccList.push(t)
templatesByMcc.set(mcc, mccList)
}
}
// ============================================================
// Public API
// ============================================================
/** O(1) lookup by template ID */
export function getTemplateById(id: string): BookingTemplate | undefined {
return templateById.get(id)
}
/** Get all templates in a group */
export function getTemplatesByGroup(group: TemplateGroup): BookingTemplate[] {
return templatesByGroup.get(group) || []
}
/** Get templates matching a specific MCC code */
export function getTemplatesByMcc(mcc: number): BookingTemplate[] {
return templatesByMcc.get(mcc) || []
}
/** Get all groups with labels and their templates */
export function getTemplateGroups(): TemplateGroupInfo[] {
const groups: TemplateGroupInfo[] = []
for (const [group, labels] of Object.entries(GROUP_LABELS)) {
const g = group as TemplateGroup
groups.push({
group: g,
label_sv: labels.sv,
label_en: labels.en,
templates: templatesByGroup.get(g) || [],
})
}
return groups
}
/**
* Fuzzy search templates by name, keywords, or description.
* Optionally filter by entity type.
*/
export function searchTemplates(query: string, entityType?: EntityType): BookingTemplate[] {
if (!query.trim()) return []
const q = query.toLowerCase()
const tokens = q.split(/\s+/).filter(Boolean)
return BOOKING_TEMPLATES.filter((t) => {
// Filter by entity applicability
if (entityType && t.entity_applicability !== 'all' && t.entity_applicability !== entityType) {
return false
}
// Check if all tokens match somewhere
return tokens.every((token) =>
t.name_sv.toLowerCase().includes(token) ||
t.name_en.toLowerCase().includes(token) ||
t.description_sv.toLowerCase().includes(token) ||
t.keywords.some((kw) => kw.toLowerCase().includes(token)) ||
t.id.includes(token)
)
})
}
/**
* Multi-signal matching against a transaction.
* Returns top 5 matches sorted by confidence descending.
*/
export function findMatchingTemplates(
transaction: Transaction,
entityType?: EntityType
): TemplateMatch[] {
const results: TemplateMatch[] = []
const isExpense = transaction.amount < 0
const isIncome = transaction.amount > 0
const descLower = (transaction.description || '').toLowerCase()
const merchantLower = (transaction.merchant_name || '').toLowerCase()
const searchText = `${descLower} ${merchantLower}`
for (const t of BOOKING_TEMPLATES) {
// Filter entity applicability
if (entityType && t.entity_applicability !== 'all' && t.entity_applicability !== entityType) {
continue
}
// Filter direction
if (t.direction === 'expense' && !isExpense) continue
if (t.direction === 'income' && !isIncome) continue
// 'transfer' templates match both directions
let score = 0
// MCC exact match: +0.4
if (transaction.mcc_code && t.mcc_codes.includes(transaction.mcc_code)) {
score += 0.4
}
// Keyword matches in description + merchant: +0.3 (proportional)
if (t.keywords.length > 0) {
let matchedKeywords = 0
for (const kw of t.keywords) {
if (searchText.includes(kw.toLowerCase())) {
matchedKeywords++
}
}
if (matchedKeywords > 0) {
score += 0.3 * Math.min(matchedKeywords / Math.min(t.keywords.length, 3), 1)
}
}
// Direction match bonus: +0.1 (only if there's already a signal)
if (score > 0 && ((t.direction === 'expense' && isExpense) || (t.direction === 'income' && isIncome))) {
score += 0.1
}
if (score > 0) {
const confidence = Math.round(score * t.auto_match_confidence * 100) / 100
results.push({ template: t, confidence })
}
}
return results
.sort((a, b) => b.confidence - a.confidence)
.slice(0, 5)
}
/**
* Convert a booking template into a MappingResult.
* Follows the same pattern as buildMappingResultFromCategory in category-mapping.ts.
*/
export function buildMappingResultFromTemplate(
template: BookingTemplate,
transaction: Transaction,
entityType: EntityType = 'enskild_firma'
): MappingResult {
const isExpense = transaction.amount < 0
const isBusiness = !template.default_private
// Resolve entity-specific accounts
let debitAccount = template.debit_account
let creditAccount = template.credit_account
if (entityType === 'aktiebolag') {
if (template.debit_account_ab) debitAccount = template.debit_account_ab
if (template.credit_account_ab) creditAccount = template.credit_account_ab
}
// Generate VAT lines
const vatLines: VatJournalLine[] = []
if (isBusiness && template.vat_treatment && template.deductibility !== 'non_deductible') {
const vatRate = getVatRate(template.vat_treatment)
if (template.vat_treatment === 'reverse_charge' && isExpense) {
// EU reverse charge: fiktiv moms (offsetting entries)
const absAmount = Math.abs(transaction.amount)
const rcLines = generateReverseChargeLines(absAmount)
for (const rcl of rcLines) {
vatLines.push({
account_number: rcl.account_number,
debit_amount: rcl.debit_amount,
credit_amount: rcl.credit_amount,
description: rcl.line_description || '',
})
}
} else if (vatRate > 0 && isExpense) {
// Input VAT deduction
const absAmount = Math.abs(transaction.amount)
const vatLine = generateInputVatLine(absAmount, vatRate)
if (vatLine) {
vatLines.push({
account_number: vatLine.account_number,
debit_amount: vatLine.debit_amount,
credit_amount: vatLine.credit_amount,
description: vatLine.line_description || '',
})
}
} else if (vatRate > 0 && !isExpense) {
// Output VAT (income)
const grossAmount = Math.abs(transaction.amount)
const vatAmount = Math.round((grossAmount * vatRate / (1 + vatRate)) * 100) / 100
let vatAccount: string
switch (template.vat_treatment) {
case 'standard_25': vatAccount = '2611'; break
case 'reduced_12': vatAccount = '2621'; break
case 'reduced_6': vatAccount = '2631'; break
default: vatAccount = '2611'
}
vatLines.push({
account_number: vatAccount,
debit_amount: 0,
credit_amount: vatAmount,
description: `Utgående moms ${vatRate * 100}%`,
})
}
}
// Build description
const description = `${template.name_sv}: ${transaction.description}`
return {
rule: null,
template_id: template.id,
debit_account: debitAccount,
credit_account: creditAccount,
risk_level: template.risk_level,
confidence: 1.0, // User explicitly selected template
requires_review: template.requires_review,
default_private: template.default_private,
vat_lines: vatLines,
description,
}
}