From 826513b4fd8e159c4aa6a25d7ab6b69c7a55b828 Mon Sep 17 00:00:00 2001 From: Jakob Wennberg <149234542+jakobwennberg@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:09:18 +0200 Subject: [PATCH] fix(tax): representation meal warning inverted the 2017 VAT rule (#313) (#1106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The restaurant/lunch warning claimed 'Momsen är inte avdragsgill sedan 2017', which is legally backwards. The 2017 reform (Prop. 2016/17:1) abolished the income-tax deduction for representation meals (IL 16 kap 2 §) but retained the VAT deduction on a base of up to 300 SEK per person excl. VAT, now ML 2023:200 13 kap 24-25 §§. The old 'ML 8:9' citation pointed at the repealed ML 1994:200. Verified against the swedish-vat compliance skill before rewording. Adds regression tests pinning the corrected message and legalBasis. Co-authored-by: Claude Fable 5 --- DECISIONS.md | 1 + lib/tax/__tests__/expense-warnings.test.ts | 40 ++++++++++++++++++++++ lib/tax/expense-warnings.ts | 4 +-- 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 lib/tax/__tests__/expense-warnings.test.ts diff --git a/DECISIONS.md b/DECISIONS.md index aa66dcea..858c911f 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -271,3 +271,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-07-21] Keep live annual-report narrative editable after a version is locked: immutable version snapshots preserve signing and filing content, while edits must remain possible to create a corrected superseding version. [2026-07-21] Restrict annual-report signature evidence transitions to the server service role and structured opaque references: browser RLS may manage only unbound pending roster rows, so route validation cannot be bypassed and evidence references cannot carry free-text personal data. [2026-07-21] Card-descriptor normalization keys on the pre-star merchant segment (post-star for processor prefixes) plus a token_subset match tier, instead of the deferred AI descriptor normalization (data_quality_master Appendix B): deterministic, mirrors into normalize_counterparty_key() so ledger-context template joins stay exact, and fixes the reported Anthropic no-signal case with no new infrastructure. Merchant history now falls back to description because card purchases never carry merchant_name. +[2026-07-22] Issue #313 fix limited to the meals warning; left "Representationsgåvor max 180 kr" on the gåvor line untouched: scope rule (only the inverted-VAT claim and repealed ML 8:9 reference), even though the swedish-vat skill lists 300 SEK as the representationsgåvor base; flagged as follow-up in the PR. diff --git a/lib/tax/__tests__/expense-warnings.test.ts b/lib/tax/__tests__/expense-warnings.test.ts new file mode 100644 index 00000000..37920416 --- /dev/null +++ b/lib/tax/__tests__/expense-warnings.test.ts @@ -0,0 +1,40 @@ +import { describe, it, expect } from 'vitest' +import { checkExpenseWarnings } from '../expense-warnings' + +describe('checkExpenseWarnings: representation meals', () => { + it('states that the VAT deduction is retained on a 300 kr/person base (2017 reform inverted this before, issue #313)', () => { + const warnings = checkExpenseWarnings('Lunch med kund på restaurang') + const representation = warnings.find((w) => w.category === 'Representation') + + expect(representation).toBeDefined() + expect(representation!.warningLevel).toBe('warning') + expect(representation!.message).toBe( + 'Måltider kan vara avdragsgilla som representation. Inkomstskatteavdraget togs bort 2017, men momsen är avdragsgill på upp till 300 kr/person (exkl. moms) enligt ML 13 kap 24-25 §§.' + ) + expect(representation!.legalBasis).toBe('IL 16 kap 2 §, ML 13 kap 24-25 §§') + }) + + it('never claims the VAT deduction was abolished and never cites the repealed ML 1994:200 chapter', () => { + const warnings = checkExpenseWarnings('Middag på restaurang') + const representation = warnings.find((w) => w.category === 'Representation') + + expect(representation).toBeDefined() + // The pre-fix text said 'Momsen är inte avdragsgill sedan 2017', which is + // legally inverted: Prop. 2016/17:1 abolished the income-tax deduction but + // retained the VAT deduction (now ML 2023:200, 13 kap 24-25 §§). + expect(representation!.message).not.toMatch(/momsen är inte avdragsgill/i) + expect(representation!.legalBasis).not.toMatch(/ML 8:9/) + }) + + it('triggers on restaurant, lunch, dinner, and fika descriptions', () => { + for (const description of ['Restaurang Prinsen', 'lunch', 'middag', 'fika med teamet']) { + const warnings = checkExpenseWarnings(description) + expect(warnings.some((w) => w.category === 'Representation')).toBe(true) + } + }) + + it('does not trigger the representation warning for unrelated descriptions', () => { + const warnings = checkExpenseWarnings('Adobe software subscription') + expect(warnings.some((w) => w.category === 'Representation')).toBe(false) + }) +}) diff --git a/lib/tax/expense-warnings.ts b/lib/tax/expense-warnings.ts index 9b9c397c..23228c2d 100644 --- a/lib/tax/expense-warnings.ts +++ b/lib/tax/expense-warnings.ts @@ -54,8 +54,8 @@ const warningPatterns: { warning: { category: 'Representation', warningLevel: 'warning', - message: 'Måltider kan vara avdragsgilla som representation med max 300 kr per person (exkl. moms). Momsen är inte avdragsgill sedan 2017.', - legalBasis: 'IL 16 kap 2§, ML 8:9', + message: 'Måltider kan vara avdragsgilla som representation. Inkomstskatteavdraget togs bort 2017, men momsen är avdragsgill på upp till 300 kr/person (exkl. moms) enligt ML 13 kap 24-25 §§.', + legalBasis: 'IL 16 kap 2 §, ML 13 kap 24-25 §§', }, }, {