Files
accounted/lib/bookkeeping/__tests__/currency-utils.test.ts
T
Jakob Wennberg 6f4573f380 feat: add foreign currency support, refactor bookkeeping engine, and improve invoice inbox document classification
- Add currency-utils module for SEK conversion with exchange rates
- Refactor createJournalEntry to use draft+commit flow preventing voucher number gaps (BFL 5 kap. 7§)
- Add foreign currency support to invoice entries with per-line SEK conversion
- Centralize category-to-account mapping into single source of truth
- Refactor invoice inbox to use shared document analyzer with document type classification (receipt, supplier invoice, government letter)
- Update mapping engine, supplier invoice entries, and transaction entries
- Fix report component rendering issues
- Add new validation schemas and tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:50:06 +01:00

98 lines
2.9 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { resolveSekAmount, buildCurrencyMetadata } from '../currency-utils'
describe('resolveSekAmount', () => {
it('returns amount as-is for SEK currency', () => {
expect(resolveSekAmount(1000, null, 'SEK', null)).toBe(1000)
})
it('returns amount as-is when currency is null (legacy data)', () => {
expect(resolveSekAmount(1000, null, null, null)).toBe(1000)
})
it('returns amount as-is when currency is undefined', () => {
expect(resolveSekAmount(1000, null, undefined, null)).toBe(1000)
})
it('returns amountSek when populated for foreign currency', () => {
expect(resolveSekAmount(100, 1150, 'EUR', 11.5)).toBe(1150)
})
it('rounds amountSek to 2 decimals', () => {
expect(resolveSekAmount(100, 1150.456, 'EUR', 11.5)).toBe(1150.46)
})
it('computes via exchangeRate when amountSek is null', () => {
expect(resolveSekAmount(100, null, 'EUR', 11.5)).toBe(1150)
})
it('rounds computed amount to 2 decimals', () => {
// 100.33 * 11.5 = 1153.795 → rounds to 1153.8
expect(resolveSekAmount(100.33, null, 'EUR', 11.5)).toBe(1153.8)
})
it('falls back to original amount when both amountSek and exchangeRate are null', () => {
expect(resolveSekAmount(100, null, 'EUR', null)).toBe(100)
})
it('falls back when exchangeRate is 0', () => {
expect(resolveSekAmount(100, null, 'EUR', 0)).toBe(100)
})
it('handles negative amounts correctly', () => {
expect(resolveSekAmount(-100, null, 'EUR', 11.5)).toBe(-1150)
})
it('prefers amountSek over exchangeRate computation', () => {
// amountSek = 1200, but exchangeRate would give 1150
expect(resolveSekAmount(100, 1200, 'EUR', 11.5)).toBe(1200)
})
it('handles zero amount', () => {
expect(resolveSekAmount(0, null, 'EUR', 11.5)).toBe(0)
})
})
describe('buildCurrencyMetadata', () => {
it('returns empty object for SEK', () => {
expect(buildCurrencyMetadata('SEK', 1000, null)).toEqual({})
})
it('returns empty object for null currency', () => {
expect(buildCurrencyMetadata(null, 1000, null)).toEqual({})
})
it('returns empty object for undefined currency', () => {
expect(buildCurrencyMetadata(undefined, 1000, null)).toEqual({})
})
it('returns currency metadata for foreign currency', () => {
expect(buildCurrencyMetadata('EUR', 100, 11.5)).toEqual({
currency: 'EUR',
amount_in_currency: 100,
exchange_rate: 11.5,
})
})
it('omits amount_in_currency when null', () => {
expect(buildCurrencyMetadata('EUR', null, 11.5)).toEqual({
currency: 'EUR',
exchange_rate: 11.5,
})
})
it('omits exchange_rate when null', () => {
expect(buildCurrencyMetadata('EUR', 100, null)).toEqual({
currency: 'EUR',
amount_in_currency: 100,
})
})
it('omits exchange_rate when 0', () => {
expect(buildCurrencyMetadata('EUR', 100, 0)).toEqual({
currency: 'EUR',
amount_in_currency: 100,
})
})
})