fix(arsredovisning): unblock the signing flow, accept foreign parent org nr, explain Fortnox underlag failures (#1738)
Batch from a real migration walkthrough (Fortnox -> Accounted, 2026-08-20): - Årsredovisning: the "Låst version" select was empty with no explanation because the only version was a draft and "Lås version för underskrift" is disabled while the four Lagstadgade upplysningar checkboxes and the content confirmation count as blockers. The select is now disabled with a hint that names the blocker count and links to Fullständighetskontroll, the four AR-NOTE-*-UNCONFIRMED issues carry remediation text, the lock button explains why it is grey, and "Markera som signerad" says what it still needs (locked version, bevisreferens, date). - Moderföretagets org.nr accepts a foreign registration identifier (CHE-123.456.789, HRB 12345, 923 609 016); personnummer shapes stay out. - Fortnox underlag discovery: log status, body and Fortnox's message on failure, show the message in the UI, treat a 400 with behörighet/scope text as scopes-required, and fall back to an unfiltered voucherfileconnections list when the financialyear filter answers 400. - Kontomapping: the Momskod column had min-w only; table-fixed collapsed it and its selects overflowed into Konfidens. Real w-72 now. - SIE import warnings pluralise correctly for one skipped voucher; the Verifikationsserie option says the source series is preserved. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Fable 5
parent
5a8dd21931
commit
e733ab7c43
@@ -36,6 +36,7 @@ import { BAS_REFERENCE } from '@/lib/bookkeeping/bas-reference'
|
||||
import type { ProviderName } from '@/lib/providers/types'
|
||||
import { errorResponseFromCode } from '@/lib/errors/get-structured-error'
|
||||
import { classifyProviderError } from '@/lib/providers/with-provider-call'
|
||||
import { FortnoxApiError, fortnoxErrorMessage } from '@/lib/providers/fortnox/client'
|
||||
import { createLogger } from '@/lib/logger'
|
||||
|
||||
const moduleLog = createLogger('extensions/arcim-migration')
|
||||
@@ -1371,7 +1372,18 @@ export const arcimMigrationExtension: Extension = {
|
||||
})
|
||||
return NextResponse.json({ success: true, dryRun, result })
|
||||
} catch (error) {
|
||||
log.error('arcim import-documents failed', error as Error)
|
||||
// "400 Bad Request" alone told us nothing when a live Fortnox
|
||||
// discovery failed (2026-08-20): keep status, Fortnox's own
|
||||
// message and a body excerpt in the log, and hand the message
|
||||
// to the UI so the user sees what the source system said.
|
||||
const providerStatus = error instanceof FortnoxApiError ? error.statusCode : undefined
|
||||
const providerMessage = fortnoxErrorMessage(error)
|
||||
log.error('arcim import-documents failed', error as Error, {
|
||||
providerStatus,
|
||||
providerMessage,
|
||||
providerBody:
|
||||
error instanceof FortnoxApiError ? error.body?.slice(0, 500) : undefined,
|
||||
})
|
||||
if (error instanceof FortnoxDocumentScopesRequiredError) {
|
||||
return errorResponseFromCode(
|
||||
'PROVIDER_DOCUMENT_SCOPES_REQUIRED',
|
||||
@@ -1380,7 +1392,11 @@ export const arcimMigrationExtension: Extension = {
|
||||
)
|
||||
}
|
||||
return errorResponseFromCode('PROVIDER_IMPORT_DOCUMENTS_FAILED', moduleLog, {
|
||||
details: { reason: error instanceof Error ? error.message : 'unknown' },
|
||||
details: {
|
||||
reason: error instanceof Error ? error.message : 'unknown',
|
||||
...(providerStatus ? { providerStatus } : {}),
|
||||
...(providerMessage ? { providerMessage } : {}),
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -35,7 +35,11 @@ import {
|
||||
downloadBokioUpload,
|
||||
type BokioUpload,
|
||||
} from '@/lib/providers/bokio/attachments'
|
||||
import { FortnoxApiError, FortnoxClient } from '@/lib/providers/fortnox/client'
|
||||
import {
|
||||
FortnoxApiError,
|
||||
FortnoxClient,
|
||||
isFortnoxPermissionError,
|
||||
} from '@/lib/providers/fortnox/client'
|
||||
import {
|
||||
downloadFortnoxArchiveFile,
|
||||
fetchFortnoxFileConnections,
|
||||
@@ -213,7 +217,7 @@ function fortnoxSource(
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
if (error instanceof FortnoxApiError && error.statusCode === 403) {
|
||||
if (isFortnoxPermissionError(error)) {
|
||||
throw new FortnoxDocumentScopesRequiredError()
|
||||
}
|
||||
throw error
|
||||
@@ -386,11 +390,7 @@ export async function importProviderDocuments(
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
provider === 'fortnox' &&
|
||||
finalError instanceof FortnoxApiError &&
|
||||
finalError.statusCode === 403
|
||||
) {
|
||||
if (provider === 'fortnox' && isFortnoxPermissionError(finalError)) {
|
||||
throw new FortnoxDocumentScopesRequiredError()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user