diff --git a/lib/reports/ink2/__tests__/ink2-engine.test.ts b/lib/reports/ink2/__tests__/ink2-engine.test.ts index c31801fb..29c7f46a 100644 --- a/lib/reports/ink2/__tests__/ink2-engine.test.ts +++ b/lib/reports/ink2/__tests__/ink2-engine.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { INK2_ACCOUNT_MAPPINGS, isAccountInMapping } from '../ink2-engine' +import { INK2_ACCOUNT_MAPPINGS, isAccountInMapping, checkBalanceWarning } from '../ink2-engine' import type { INK2SRUCode } from '../types' /** @@ -255,3 +255,43 @@ describe('INK2 Account Mappings', () => { }) }) }) + +describe('checkBalanceWarning', () => { + it('returns null when perfectly balanced', () => { + expect(checkBalanceWarning(100000, 100000)).toBeNull() + }) + + it('returns null for 1 kr difference (within rounding tolerance)', () => { + expect(checkBalanceWarning(100000, 100001)).toBeNull() + expect(checkBalanceWarning(100001, 100000)).toBeNull() + }) + + it('returns null for 2 kr difference (within rounding tolerance)', () => { + expect(checkBalanceWarning(100000, 100002)).toBeNull() + expect(checkBalanceWarning(100002, 100000)).toBeNull() + }) + + it('returns warning for 3 kr difference (exceeds tolerance)', () => { + expect(checkBalanceWarning(100000, 100003)).not.toBeNull() + expect(checkBalanceWarning(100003, 100000)).not.toBeNull() + }) + + it('returns null when totals are zero', () => { + expect(checkBalanceWarning(0, 0)).toBeNull() + }) + + it('returns null when both totals are zero (no data)', () => { + expect(checkBalanceWarning(0, 0)).toBeNull() + }) + + it('returns warning when assets are zero but equity/liabilities exist', () => { + expect(checkBalanceWarning(0, 5)).not.toBeNull() + }) + + it('includes amounts in warning message', () => { + const warning = checkBalanceWarning(100000, 100005) + expect(warning).toContain('100000') + expect(warning).toContain('100005') + expect(warning).toContain('5') + }) +}) diff --git a/lib/reports/ink2/ink2-engine.ts b/lib/reports/ink2/ink2-engine.ts index 56bb44fb..a775f9ba 100644 --- a/lib/reports/ink2/ink2-engine.ts +++ b/lib/reports/ink2/ink2-engine.ts @@ -194,6 +194,20 @@ function roundToKrona(value: number): number { return Math.round(value) } +/** + * Check if the balance sheet totals differ beyond the expected rounding tolerance. + * Each ruta is independently rounded to whole kronor for SRU output, so with 11+ + * rutor the accumulated rounding can produce a 1-2 kr difference. + */ +export function checkBalanceWarning(totalAssets: number, totalEquityLiabilities: number): string | null { + const balanceDiff = Math.abs(totalAssets - totalEquityLiabilities) + const ROUNDING_TOLERANCE_KR = 2 + if (balanceDiff > ROUNDING_TOLERANCE_KR && (totalAssets > 0 || totalEquityLiabilities > 0)) { + return `Balansräkningen är inte i balans. Tillgångar: ${totalAssets} kr, Eget kapital och skulder: ${totalEquityLiabilities} kr (differens: ${balanceDiff} kr).` + } + return null +} + /** * Generate INK2 declaration for a fiscal period */ @@ -349,18 +363,16 @@ export async function generateINK2Declaration( // Add warnings if (!(period as FiscalPeriod).is_closed) { - warnings.push('Räkenskapsåret är inte stängt. Siffrorna kan ändras.') + warnings.push('Räkenskapsåret är inte stängt — deklarationen kan genereras, men siffrorna kan ändras om fler bokföringar görs.') } if (totalAssets === 0 && totalEquityLiabilities === 0 && rutor['7310'] === 0) { warnings.push('Inga bokförda transaktioner hittades för perioden.') } - const balanceDiff = Math.abs(totalAssets - totalEquityLiabilities) - if (balanceDiff > 0 && totalAssets > 0) { - warnings.push( - `Balansräkningen är inte i balans. Tillgångar: ${totalAssets} kr, Eget kapital och skulder: ${totalEquityLiabilities} kr (differens: ${balanceDiff} kr).` - ) + const balanceWarning = checkBalanceWarning(totalAssets, totalEquityLiabilities) + if (balanceWarning) { + warnings.push(balanceWarning) } return { diff --git a/lib/reports/ne-bilaga/ne-engine.ts b/lib/reports/ne-bilaga/ne-engine.ts index b5aa4b51..e4e16f83 100644 --- a/lib/reports/ne-bilaga/ne-engine.ts +++ b/lib/reports/ne-bilaga/ne-engine.ts @@ -302,7 +302,7 @@ export async function generateNEDeclaration( // Add warnings if (!(period as FiscalPeriod).is_closed) { - warnings.push('Räkenskapsåret är inte stängt. Siffrorna kan ändras.') + warnings.push('Räkenskapsåret är inte stängt — deklarationen kan genereras, men siffrorna kan ändras om fler bokföringar görs.') } if (rutor.R11 === 0 && totalRevenue === 0) {