Refactor bookkeeping error handling and introduce new error classes (#356)

- Introduced new error classes for better error categorization:
  - JournalEntryNotBalancedError
  - FiscalPeriodNotFoundError
  - EntryDateOutsideFiscalPeriodError
  - JournalEntryNotFoundError
  - CannotReverseNonPostedError
  - CannotCorrectNonPostedError
  - EntryAlreadyReversedError
  - CurrencyRevaluationAlreadyExistsError
  - InvalidMappingResultError
  - BookkeepingDatabaseError

- Updated existing functions in engine.ts and transaction-entries.ts to throw specific errors instead of generic ones.
- Enhanced error response handling in get-error-message.ts to provide localized messages for new error types.
- Added unit tests for new error classes and error handling functions to ensure correctness and coverage.
This commit is contained in:
Mattsson
2026-04-23 14:49:45 +02:00
committed by GitHub
parent e137a9f452
commit 0222e084bb
32 changed files with 944 additions and 126 deletions
@@ -15,6 +15,7 @@ import { Badge } from '@/components/ui/badge'
import { AccountNumber } from '@/components/ui/account-number'
import AccountCombobox from '@/components/bookkeeping/AccountCombobox'
import { useToast } from '@/components/ui/use-toast'
import { getErrorMessage } from '@/lib/errors/get-error-message'
import { Plus, Trash2 } from 'lucide-react'
import type { JournalEntry, JournalEntryLine, BASAccount } from '@/types'
@@ -109,7 +110,10 @@ export default function CorrectionEntryDialog({ entry, open, onOpenChange, onCor
const result = await res.json()
if (!res.ok) {
throw new Error(result.error || 'Failed to create correction')
const error = new Error('Failed to create correction') as Error & { body?: unknown; status?: number }
error.body = result
error.status = res.status
throw error
}
const correctedId = result.data?.corrected?.id
@@ -126,9 +130,10 @@ export default function CorrectionEntryDialog({ entry, open, onOpenChange, onCor
onOpenChange(false)
onCorrected()
} catch (err) {
const anyErr = err as { body?: unknown; status?: number }
toast({
title: 'Fel',
description: err instanceof Error ? err.message : 'Kunde inte skapa ändringsverifikation',
description: getErrorMessage(anyErr.body ?? err, { context: 'journal_entry', statusCode: anyErr.status }),
variant: 'destructive',
})
} finally {
+7 -2
View File
@@ -16,6 +16,7 @@ import { Badge } from '@/components/ui/badge'
import { useToast } from '@/components/ui/use-toast'
import AccountCombobox from '@/components/bookkeeping/AccountCombobox'
import { proposePaymentLines } from '@/lib/bookkeeping/propose-payment-lines'
import { getErrorMessage } from '@/lib/errors/get-error-message'
import { formatCurrency } from '@/lib/utils'
import { createClient } from '@/lib/supabase/client'
import { useCompany } from '@/contexts/CompanyContext'
@@ -187,15 +188,19 @@ export default function PaymentBookingDialog({
if (!response.ok) {
const data = await response.json()
throw new Error(data.error || 'Kunde inte markera som betald')
const error = new Error('Kunde inte markera som betald') as Error & { body?: unknown; status?: number }
error.body = data
error.status = response.status
throw error
}
onOpenChange(false)
onSuccess()
} catch (error) {
const anyErr = error as { body?: unknown; status?: number }
toast({
title: 'Bokföring misslyckades',
description: error instanceof Error ? error.message : 'Försök igen.',
description: getErrorMessage(anyErr.body ?? error, { context: 'invoice', statusCode: anyErr.status }),
variant: 'destructive',
})
}