fix: INK2 rounding tolerance and clearer warnings (#197)
* fix: add rounding tolerance to INK2 balance check and clarify warnings INK2/SRU rounds each ruta independently to whole kronor, so with 11+ rutor the accumulated rounding can produce a 1-2 kr difference that triggered a false "balance sheet not in balance" warning. Add a 2 kr tolerance. Also clarify the unclosed fiscal year warning to indicate that generation still works. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: also warn when equity/liabilities exist but assets are zero Address Greptile review feedback — the balance check guard should trigger when either side has a non-zero total, not only when assets > 0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
20818e3283
commit
6c79f21679
@@ -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')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user