51b68afc87
A user with a September-to-August fiscal year could not sign off 1930: the dialog let them press Signera, the server refused, and the dialog showed "Något gick fel. Försök igen." Three defects, one flow: - signOffAccount judged a bank account over the calendar year from 1 January (the getAccountStatus default) while the page the signer looked at was scoped to the fiscal period. The sign-off now resolves the fiscal period covering through_date and judges from its start, for every caller (dashboard, v1, MCP, pending-operation executor). - The dialog decided whether the "sign anyway" override was needed from the page tile, which can be scoped to a narrower range. It now previews the exact sign-off with dry_run on open and on every date change, and NOT_RECONCILED carries the unexplained amount in details so the warning can name it. - The routes passed the refusal through getErrorMessage(), which did not know the sign-off codes and replaced the Swedish text with its generic fallback. The codes are now in the structured error registry with a thrown_message_sv flag: the mapper passes the thrower's text (dates, amounts) through verbatim and English users get message_en. Claude-Session: https://claude.ai/code/session_01YDH3nqA8QtMA8WKTKZCMsA Signed-off-by: Emil <emilmattsson14@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
61 lines
2.4 KiB
TypeScript
61 lines
2.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { getErrorMessage } from '../get-error-message'
|
|
import { getErrorEntry } from '../structured-errors'
|
|
import { ReconciliationSignoffError, type SignoffErrorCode } from '@/lib/reconciliation/signoff'
|
|
|
|
/**
|
|
* The sign-off refusals are composed in Swedish at the throw site (a date, an
|
|
* amount). Before these codes were registered, getErrorMessage() fell through
|
|
* to its generic fallback and the dialog showed "Något gick fel. Försök igen."
|
|
* for a refused sign-off.
|
|
*/
|
|
const CODES: SignoffErrorCode[] = [
|
|
'INVALID_DATE',
|
|
'DATE_IN_FUTURE',
|
|
'NOT_FETCHED_THROUGH',
|
|
'OUTSIDE_UNKNOWN',
|
|
'NOT_RECONCILED',
|
|
'NOTE_REQUIRED',
|
|
'ALREADY_SIGNED_OFF',
|
|
'SIGNOFF_NOT_FOUND',
|
|
'ALREADY_REOPENED',
|
|
'SIGNOFF_RACE',
|
|
'EXTERNAL_BALANCE_NOT_ALLOWED',
|
|
]
|
|
|
|
describe('reconciliation sign-off codes in the error registry', () => {
|
|
it('registers every code with a Swedish and an English message', () => {
|
|
for (const code of CODES) {
|
|
const entry = getErrorEntry(code)
|
|
expect(entry, code).toBeDefined()
|
|
expect(entry?.message_sv, code).toMatch(/\S/)
|
|
expect(entry?.message_en, code).toMatch(/\S/)
|
|
expect(entry?.thrown_message_sv, code).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('passes the thrown Swedish text through verbatim, runtime detail included', () => {
|
|
const err = new ReconciliationSignoffError(
|
|
'Skattekontot är hämtat t.o.m. 2026-08-20. Hämta igen innan du stämmer av ett senare datum.',
|
|
'NOT_FETCHED_THROUGH',
|
|
)
|
|
expect(getErrorMessage(err)).toBe(
|
|
'Skattekontot är hämtat t.o.m. 2026-08-20. Hämta igen innan du stämmer av ett senare datum.',
|
|
)
|
|
const refused = new ReconciliationSignoffError(
|
|
'Kontot har en oförklarad differens. Koppla eller bokför raderna först, eller signera med en notering.',
|
|
'NOT_RECONCILED',
|
|
{ unexplained_difference: 53717 },
|
|
)
|
|
expect(getErrorMessage(refused)).toBe(
|
|
'Kontot har en oförklarad differens. Koppla eller bokför raderna först, eller signera med en notering.',
|
|
)
|
|
expect(getErrorMessage(refused)).not.toMatch(/Något gick fel/)
|
|
})
|
|
|
|
it('gives English users the registry text', () => {
|
|
const err = new ReconciliationSignoffError('Kontot har en oförklarad differens.', 'NOT_RECONCILED')
|
|
expect(getErrorMessage(err, { locale: 'en' })).toBe(getErrorEntry('NOT_RECONCILED')?.message_en)
|
|
})
|
|
})
|