fix(bokslut): map computer/vehicle depreciation to standard 7832 so it resolves (#755) (#822)

* fix(bokslut): map computer/vehicle depreciation to standard 7832 so it resolves (#755)

The computer asset category mapped depreciation expense to 7833 and vehicle to
7834, but neither is in the standard BAS catalog (7834/7835 were removed as
non-standard in #463, guarded by bas-reference.test.ts). Because
backfillStandardBASAccounts only seeds accounts present in BAS_REFERENCE, the
engine threw AccountsNotInChartError on minimal charts and annual depreciation
was blocked.

- Remap computer and vehicle depreciation expense to 7832 (Avskrivningar på
  inventarier, verktyg och installationer). Both 1240 (Bilar) and 1250 (Datorer)
  sit in the maskiner-och-inventarier asset range, so 7832 is the correct
  standard depreciation account — same one equipment already uses. The asset
  register still separates them via 1240/1249 and 1250/1259 on the balance sheet.
- A regression guard surfaced a second gap: other_tangible mapped to 1280/1289,
  but 1280 is 'Pågående nyanläggningar/förskott' and 1289 is not a BAS account.
  Remap other_tangible to 1290/1299 ('Övriga materiella anläggningstillgångar' +
  its ack. avskrivningar) — the BAS-correct accounts, and the range the iXBRL K2
  mapper already classifies other_tangible under. Keeps accumulated = asset + 9.
- Add a guard test asserting every DEFAULT_ACCOUNTS_BY_CATEGORY account resolves
  in BAS_REFERENCE, so a future missing account fails CI instead of a user's
  depreciation run.

No new BAS accounts are added, so the non-standard-accounts guard stays green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(dashboard): drop the duplicate next-best-action hero for a single CTA

The agent-built dashboard showed a 'next best action' hero card AND the unified
'Att göra' worklist below it — two surfaces pointing at the same work (book
transactions, unpaid invoices). Remove the hero so the page leads with metrics +
the single 'Att göra' worklist, giving one unambiguous CTA surface instead of
two. Drops the now-unused nextBestAction computation and the Receipt/
ArrowLeftRight/Clock imports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-06-29 21:47:46 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 663e1232a4
commit cb01b946fc
3 changed files with 40 additions and 102 deletions
+20 -3
View File
@@ -5,6 +5,7 @@ import {
disposeAsset,
updateAsset,
} from '../assets/asset-service'
import { getBASReference } from '@/lib/bookkeeping/bas-reference'
import type { Asset } from '@/types'
vi.mock('@/lib/bookkeeping/engine', () => ({
@@ -23,9 +24,9 @@ describe('DEFAULT_ACCOUNTS_BY_CATEGORY', () => {
land_improvement: { asset: '1150', accumulated: '1159', expense: '7824' },
machinery: { asset: '1210', accumulated: '1219', expense: '7831' },
equipment: { asset: '1220', accumulated: '1229', expense: '7832' },
vehicle: { asset: '1240', accumulated: '1249', expense: '7834' },
computer: { asset: '1250', accumulated: '1259', expense: '7833' },
other_tangible: { asset: '1280', accumulated: '1289', expense: '7839' },
vehicle: { asset: '1240', accumulated: '1249', expense: '7832' },
computer: { asset: '1250', accumulated: '1259', expense: '7832' },
other_tangible: { asset: '1290', accumulated: '1299', expense: '7839' },
} as const
expect(DEFAULT_ACCOUNTS_BY_CATEGORY).toEqual(expected)
})
@@ -48,6 +49,22 @@ describe('DEFAULT_ACCOUNTS_BY_CATEGORY', () => {
expect(expense).toMatch(/^78\d{2}$/)
}
})
// Regression guard for #755: 7833/7834 were referenced here but absent from
// the BAS reference, so backfillStandardBASAccounts could not seed them and
// annual depreciation threw AccountsNotInChartError. Every account in the
// triple must resolve in BAS_REFERENCE — otherwise the lazy backfill silently
// can't add it and the depreciation posting fails on minimal charts.
it('every account in the triple exists in the BAS reference (backfillable)', () => {
for (const cat of Object.keys(DEFAULT_ACCOUNTS_BY_CATEGORY) as Array<
keyof typeof DEFAULT_ACCOUNTS_BY_CATEGORY
>) {
const { asset, accumulated, expense } = DEFAULT_ACCOUNTS_BY_CATEGORY[cat]
for (const account of [asset, accumulated, expense]) {
expect(getBASReference(account), `${cat}: ${account} missing from BAS reference`).toBeDefined()
}
}
})
})
describe('disposeAsset — gain/loss account selection', () => {
+13 -5
View File
@@ -12,8 +12,16 @@ import type {
/**
* Default BAS account triples per category. The user can override at create
* time; these only kick in when the form doesn't specify accounts. Matches
* the seeded BAS 2020 chart (lib/bookkeeping/bas-data/).
* time; these only kick in when the form doesn't specify accounts. Every
* account here MUST exist in BAS_REFERENCE (lib/bookkeeping/bas-data/) so the
* engine's backfillStandardBASAccounts can seed it on a minimal chart —
* otherwise depreciation throws AccountsNotInChartError (#755). A guard test in
* asset-service.test.ts enforces that invariant.
*
* vehicle (1240) and computer (1250) both sit in the maskiner-och-inventarier
* asset range, so their depreciation maps to 7832 (Avskrivningar på
* inventarier, verktyg och installationer) — 7833/7834 are not in the standard
* BAS catalog (removed as non-standard in #463).
*/
export const DEFAULT_ACCOUNTS_BY_CATEGORY: Record<
AssetCategory,
@@ -24,9 +32,9 @@ export const DEFAULT_ACCOUNTS_BY_CATEGORY: Record<
land_improvement: { asset: '1150', accumulated: '1159', expense: '7824' },
machinery: { asset: '1210', accumulated: '1219', expense: '7831' },
equipment: { asset: '1220', accumulated: '1229', expense: '7832' },
vehicle: { asset: '1240', accumulated: '1249', expense: '7834' },
computer: { asset: '1250', accumulated: '1259', expense: '7833' },
other_tangible: { asset: '1280', accumulated: '1289', expense: '7839' },
vehicle: { asset: '1240', accumulated: '1249', expense: '7832' },
computer: { asset: '1250', accumulated: '1259', expense: '7832' },
other_tangible: { asset: '1290', accumulated: '1299', expense: '7839' },
}
export interface CreateAssetInput {