Files
accounted/lib/import/bank-file/__tests__/currency-summary.test.ts
T
Jakob WennbergandClaude Fable 5 bb78f8fce8 fix(import): per-currency totals and row currency in bank-file preview (#1178)
* fix(import): per-currency totals and row currency in bank-file preview

Fixes #1170. ParsedBankTransaction carries a per-row currency (Wise
emits genuinely mixed rows; camt.053 reads Ccy per entry), but the
preview and confirm steps formatted every amount as kr and rendered
parser-level income/expense totals that sum across currencies.

Adds summarizeByCurrency() (income positive / expenses negative, ore
rounding, SEK default) and renders one total line per currency on both
steps; preview table rows format amount and balance with the row's own
currency.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(import): use roundOre from lib/money (antipattern ratchet)

The naive Math.round(x * 100) / 100 form is blocked by check:guards
(subtly wrong on exact-half values); lib/money.roundOre is canonical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 12:58:47 +02:00

45 lines
1.4 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { summarizeByCurrency } from '../currency-summary'
import type { ParsedBankTransaction } from '../types'
function tx(overrides: Partial<ParsedBankTransaction>): ParsedBankTransaction {
return {
date: '2026-07-01',
description: 'Test',
amount: 0,
currency: 'SEK',
...overrides,
}
}
describe('summarizeByCurrency', () => {
it('groups income and expenses per currency instead of mixing them', () => {
const result = summarizeByCurrency([
tx({ amount: 2500, currency: 'USD' }),
tx({ amount: -100.5, currency: 'USD' }),
tx({ amount: 1000, currency: 'SEK' }),
tx({ amount: -250, currency: 'SEK' }),
tx({ amount: -30, currency: 'EUR' }),
])
expect(result).toEqual([
{ currency: 'EUR', total_income: 0, total_expenses: -30 },
{ currency: 'SEK', total_income: 1000, total_expenses: -250 },
{ currency: 'USD', total_income: 2500, total_expenses: -100.5 },
])
})
it('defaults a missing currency to SEK and rounds to ore', () => {
const result = summarizeByCurrency([
tx({ amount: 0.105, currency: '' }),
tx({ amount: 0.105, currency: '' }),
])
expect(result).toEqual([{ currency: 'SEK', total_income: 0.21, total_expenses: 0 }])
})
it('returns an empty list for no transactions', () => {
expect(summarizeByCurrency([])).toEqual([])
})
})