diff --git a/components/dashboard/DashboardContent.tsx b/components/dashboard/DashboardContent.tsx
index 905f1c61..c2aa9112 100644
--- a/components/dashboard/DashboardContent.tsx
+++ b/components/dashboard/DashboardContent.tsx
@@ -11,11 +11,8 @@ import { TaxTodoWidget } from '@/components/deadlines/TaxTodoWidget'
import NewUserChecklist from '@/components/onboarding/NewUserChecklist'
import AttGoraSection from '@/components/dashboard/AttGoraSection'
import {
- Receipt,
- ArrowLeftRight,
ChevronRight,
CheckCircle2,
- Clock,
ArrowRight,
MessageCircle,
} from 'lucide-react'
@@ -114,67 +111,15 @@ export default function DashboardContent({ companyId, summary, worklist, suggest
// header so the tile and the section never disagree.
const todoCount = worklist.total + (summary.expiringBankConnections?.length ?? 0)
- // Pick the single most-urgent next action so the launchpad surfaces one
- // unambiguous CTA. Order matches the friction we actually want to remove
- // first: stale → overdue → uncategorized → unpaid → all clear.
- const nextBestAction = (() => {
- if (summary.staleUncategorizedCount > 0) {
- return {
- href: '/transactions',
- title: 'Gamla transaktioner väntar',
- body: `${summary.staleUncategorizedCount} transaktion${summary.staleUncategorizedCount === 1 ? '' : 'er'} äldre än 14 dagar saknar bokföring.`,
- cta: 'Bokför nu',
- tone: 'destructive' as const,
- icon: Clock,
- }
- }
- if (summary.overdueInvoicesCount > 0) {
- return {
- href: '/invoices?status=unpaid',
- title: 'Förfallna fakturor',
- body: `${summary.overdueInvoicesCount} st · ${formatCurrency(summary.unpaidInvoicesTotal)}`,
- cta: 'Gå till fakturor',
- tone: 'destructive' as const,
- icon: Receipt,
- }
- }
- if (worklist.counts.book_transaction > 0) {
- const n = worklist.counts.book_transaction
- return {
- href: '/transactions',
- title: 'Transaktioner att bokföra',
- body: `${n} obokförd${n === 1 ? '' : 'a'} transaktion${n === 1 ? '' : 'er'}.`,
- cta: 'Bokför nu',
- tone: 'primary' as const,
- icon: ArrowLeftRight,
- }
- }
- if (summary.unpaidInvoicesCount > 0) {
- return {
- href: '/invoices?status=unpaid',
- title: 'Obetalda fakturor',
- body: `${summary.unpaidInvoicesCount} st · ${formatCurrency(summary.unpaidInvoicesTotal)}`,
- cta: 'Visa fakturor',
- tone: 'primary' as const,
- icon: Receipt,
- }
- }
- return {
- href: '/invoices/new',
- title: 'Allt är ikapp',
- body: 'Inga obokförda transaktioner och inga obetalda fakturor. Skicka nästa faktura?',
- cta: 'Skapa faktura',
- tone: 'neutral' as const,
- icon: CheckCircle2,
- }
- })()
-
return (
- {!agentBuilt ? (
- /* Build-assistant hero — shown until the company has a verified
- agent_profile. Takes the hero slot so existing/migrated users get a
- clear prompt instead of a full-screen onboarding takeover. */
+ {/* Build-assistant hero — shown only until the company has a verified
+ agent_profile, so existing/migrated users get a clear prompt instead
+ of a full-screen onboarding takeover. Once the assistant is built the
+ dashboard leads with the metrics + the unified "Att göra" worklist
+ below; we deliberately drop a next-best-action hero here so the page
+ has a single CTA surface instead of two that point at the same work. */}
+ {!agentBuilt && (
@@ -199,38 +144,6 @@ export default function DashboardContent({ companyId, summary, worklist, suggest
- ) : (
- /* Next best action — single hero card, shown for every agent-built
- company regardless of nav density so there is always one clear CTA */
-
-
-
-
-
-
-
-
-
{nextBestAction.title}
-
{nextBestAction.body}
-
-
- {nextBestAction.cta}
-
-
-
-
-
-
)}
{/* Key metrics — 4 compact cards */}
diff --git a/lib/bokslut/__tests__/asset-service.test.ts b/lib/bokslut/__tests__/asset-service.test.ts
index cba4d210..1633a3bb 100644
--- a/lib/bokslut/__tests__/asset-service.test.ts
+++ b/lib/bokslut/__tests__/asset-service.test.ts
@@ -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', () => {
diff --git a/lib/bokslut/assets/asset-service.ts b/lib/bokslut/assets/asset-service.ts
index 0751dbb4..0ec95bf4 100644
--- a/lib/bokslut/assets/asset-service.ts
+++ b/lib/bokslut/assets/asset-service.ts
@@ -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 {