Em dashes (—) and en dashes (–) had spread across comments, docs, tests,
and a few UI strings, reading as AI-generated boilerplate rather than
house style. Replaced each with punctuation matching its context: colon
for explanatory clauses, comma for asides, plain hyphen for numeric/legal
ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for
paired-dash asides. messages/en.json and messages/sv.json were fixed by
hand together to keep sv/en in sync.
Left untouched where the dash is the functional subject rather than
decorative punctuation: date-range-parser.ts's separator regex,
charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE
encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the
agent system-prompt files that already instruct against em dashes, and
a golden iXBRL test fixture compared byte-for-byte.
Also fixes two bugs surfaced along the way: an off-by-one in
ApiKeysPanel's scope-label split (a leftover from an earlier partial
pass), and a charset-repair test that had lost the literal en-dash it
exists to verify.
Regenerated the agent atom seed migration (skills:generate) since 27
SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes,
with an explicit carve-out for the functional-dash cases above.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
`syncMappedAccounts` pages the company's full chart via `fetchAllRows` to avoid
the silent 1000-row PostgREST cap, but the query had no `.order()`. Like the
report queries fixed in #811, PostgREST `.range()` paging is only correct with a
stable total order — without it, a chart larger than one page could duplicate or
skip accounts across page boundaries, corrupting the existing-account Map and
causing spurious create/update churn on import.
Order on the unique `account_number` (stable total order; the result is read
into a Map so the order is invisible to callers). Extend the test mock's query
chain to include `.order()`.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(import): add syncMappedAccounts helper for account create + rename
Single home for the create-missing-accounts logic that exists in three
near-identical copies (executeSIEImport, the SIE execute route, and the
arcim-migration extension), plus a new rename pass that carries customized
SIE #KONTO names into accounts that already exist (e.g. K1-seeded defaults).
The file's name applies only to identity mappings (source === target);
remapped targets keep their BAS/current name. With updateAccountNames=false
the behavior matches the legacy code exactly. Not wired up yet.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(import): preserve SIE #KONTO account names; add updateAccountNames option
Customer report: account names customized in Fortnox did not follow into
Accounted via SIE import. The import always used BAS default names for
accounts in the BAS reference and never touched accounts that already
existed (the K1-seeded chart), so the file's names were silently dropped.
executeSIEImport now routes account creation through syncMappedAccounts,
which prefers the file's #KONTO name for identity-mapped accounts and
renames existing accounts whose name differs (surfaced as a warning).
New option updateAccountNames (default true) restores the old behavior
when disabled. The duplicated pre-create blocks in the execute route and
the arcim-migration extension are removed — executeSIEImport owns account
sync on every path now, including the Fortnox re-sync (idempotent renames).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mcp): expose update_account_names on gnubok_import_sie
Optional boolean on the tool schema, staged into the pending operation and
threaded through commitImportSie to executeSIEImport. Defaults to true at
both stage and commit time — the commit-side default also covers operations
staged before the param existed (Boolean(undefined) would have silently
flipped it off).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(api): v1 SIE import generated no account mappings
The route passed [] as mappings to executeSIEImport, which the
mapping-coverage guard (added in #613) rejects for any real file — and
before that guard, every voucher was silently skipped as unmapped. The
route has never produced a working import for files with vouchers.
Generate mappings server-side from the file's #KONTO records plus stored
per-company overrides (same as the dashboard execute route), reject
unmappable files with a clean 400 before the operation row is created,
and expose options.updateAccountNames (default true).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(import): "Använd kontonamn från filen" toggle in import review step
New switch (default on) controlling whether the SIE file's #KONTO names
are carried into the chart of accounts. Helper text shows how many
identity-mapped accounts carry names that differ from the BAS defaults.
The page already serializes the whole options object to the execute
route, so no further wiring is needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(import): address PR #669 review — parallel renames, rename audit trail
- Rename pass now runs UPDATEs concurrently in bounded batches of 25
(greptile P2): a re-sync with many custom names no longer serializes
N round trips, and a pathological full-chart rename cannot stampede
the API. Per-rename failures stay non-fatal via Promise.allSettled.
- Persist the per-account rename detail (number, from, to) into
sie_imports.migration_documentation as accountRenames — the
behandlingshistorik record per BFNAR 2013:2 (swedish-compliance
review); the result warnings only carry the count.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>