Files
accounted/lib/bookkeeping/booking-templates.ts
T

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', 'mistral', 'claude', 'gemini'],
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', 'kontor'],
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, 20)
}
/**
* 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,
}
}