fix(import): show "created on import" as the mapping target for source accounts the chart lacks (#2342)

The guided Fortnox import self-mapped a source account that exists in
neither the company chart nor BAS (4599) and then rendered its Malkonto
select blank, because the dropdown only knew chart + BAS accounts. The
row looked unmapped and unmappable while the import created the account
correctly. A nameless account (referenced by #TRANS without #KONTO) was
worse: the mapper refused the self-map, so it stayed unmapped with no
self-target to pick.

- account-mapper: the bas_range self-map no longer requires a #KONTO
  name; unmapped now means exactly "outside 1000-8999". isValidBASRange
  exported as the auto-create boundary.
- AccountMappingStep (shared by both wizards): a target the list cannot
  name is an explicit "<nr> <name> (skapas vid importen)" option, a
  "nya konton skapas" badge/filter lists them, out-of-range accounts
  that block Continue are named, nameless sources say so.
- sie-import: skippedVouchers.unmappedAccounts (per account, voucher
  count) via summarizeUnmappedSkips; warning names the accounts.
- Migration result step: names created accounts and the accounts behind
  "med ej kopplade konton".

Closes #2212


Claude-Session: https://claude.ai/code/session_019SaJfqNi4VmsG8FMKq99G6

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-09-06 18:39:36 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Fable 5.1
parent ea4da0eb07
commit 162de2128a
10 changed files with 318 additions and 14 deletions
@@ -1490,6 +1490,7 @@ function openingBalanceSentence(ob: NonNullable<NonNullable<ImportResult['detail
* errors keep strong color. Nothing folds away, nothing gets a box.
*/
function FiscalYearLine({ result, index }: { result: ImportResult; index: number }) {
const t = useTranslations('extensions')
const status = getFYStatus(result)
const d = result.details
const fyLabel = d?.fiscalYear
@@ -1503,7 +1504,16 @@ function FiscalYearLine({ result, index }: { result: ImportResult; index: number
if (d.skippedVouchers.empty > 0) parts.push(`${d.skippedVouchers.empty} tomma`)
if (d.skippedVouchers.unbalanced > 0) parts.push(`${d.skippedVouchers.unbalanced} obalanserade`)
if (d.skippedVouchers.singleLine > 0) parts.push(`${d.skippedVouchers.singleLine} enradiga`)
if (d.skippedVouchers.unmapped > 0) parts.push(`${d.skippedVouchers.unmapped} med ej kopplade konton`)
if (d.skippedVouchers.unmapped > 0) {
// Name the accounts (issue #2212): a count alone sends the user to diff
// the general ledger against the source system by hand.
const perAccount = (d.skippedVouchers.unmappedAccounts ?? [])
.map((a) => `konto ${a.account}: ${a.vouchers}`)
.join(', ')
parts.push(
`${d.skippedVouchers.unmapped} med ej kopplade konton${perAccount ? ` (${perAccount})` : ''}`
)
}
warningSentences.push(
`${d.skippedVouchers.total} verifikationer hoppades över (${parts.join(', ')}): saldon har justerats automatiskt via omföringsverifikation.`
)
@@ -1526,6 +1536,12 @@ function FiscalYearLine({ result, index }: { result: ImportResult; index: number
)
const infoLines: string[] = []
// Accounts the import inserted into the chart (self-mapped source accounts
// the company did not have). Said out loud so "did the import go right?"
// has an answer on screen instead of in a chart-of-accounts diff.
if (result.accountsCreated && result.accountsCreated > 0) {
infoLines.push(t('ext_arcim_accounts_created', { count: result.accountsCreated }))
}
if (d?.openingBalance) infoLines.push(openingBalanceSentence(d.openingBalance))
if (d?.migrationAdjustment?.created) {
infoLines.push(