feat(ledger): native chart of accounts — template picker and sever disposition - #363
Conversation
…sposition Consumes @robosystems/client 1.16.0 (the native chart surface from robosystems #1378 and #1379). The chart-of-accounts page's empty state becomes a template picker: it lists the shipped templates (chartTemplates), takes an optional legal form for the equity mapping, runs initialize-chart-of-accounts and reloads the page with the new chart. One-time by design; a 409 from a graph that already has a chart surfaces as the alert. Deleting a QuickBooks connection now asks which way the books go: keep the connection revivable (disconnect, the default and today's behaviour) or sever it and go native with the chart QuickBooks created. The modal is its own component; other providers keep the single confirmation. The provider label map is exported from ConnectionCard so the dialog names the provider instead of interpolating the slug. Claude-Session: https://claude.ai/code/session_0188CbjDiNBtxdEYjSJ5Y7mX
|
Change classification: normal — platform or application code changed. A normal change carries a documented automated review on this pull request before merge, in place of a second human approver. The |
|
@claude please review this PR |
|
Claude finished @jfrench9's task in 1m 52s —— View job Review
Nice, focused PR — the template picker and the sever/disconnect fork are both clean, well-tested implementations of the two flows described. Two things worth a look before/around merge: 1. Both setLoadError(err instanceof Error ? err.message : 'Failed to load chart templates.')
...
setInitError(err instanceof Error ? err.message : 'Failed to initialize the chart of accounts.')Per 2. Template picker can render alongside a genuine load failure ( The empty-state branch is keyed only on Minor / non-blocking:
Test coverage for both new components ( |
Review fixes on #363. The picker now runs SDK errors through friendlyError instead of showing the raw "<label> failed: {json}" envelope, and the one-time refusal (a chart already exists) gets its own mapping. The chart page no longer shows the picker under a load-failure card, since an empty account list also follows a failed load. The template cards are real radio inputs inside a fieldset, matching the disposition dialog. Claude-Session: https://claude.ai/code/session_0188CbjDiNBtxdEYjSJ5Y7mX
Summary
The app side of the native accounting cutover (RoboFinSystems/robosystems#1378, #1379; client 1.16.0): the chart-of-accounts page's empty state becomes a template picker that creates the chart in one step, and deleting a QuickBooks connection asks whether to keep it revivable or sever it and go native.
Changes
Chart of accounts (
ledger/chart-of-accounts)components/ChartTemplatePicker.tsx: lists the shipped templates viaclients.ledger.listChartTemplates, takes an optional legal form for the equity mapping (corporation / LLC / partnership, defaulting to the entity's own), runsclients.ledger.initializeChartOfAccounts, and hands the result back. A refusal (409 once a chart exists) or a load failure surfaces as an alert. The copy tells a QuickBooks user to skip it, since their chart arrives with the first sync.content.tsx: the "No Accounts Found / import accounting data" empty state is replaced by the picker when a graph is selected; areloadKeyre-runs the loader for the same graph once the chart exists, so the new accounts replace the empty state without a route bounce.Connections (
connections)components/DeleteConnectionModal.tsxwrappingConfirmModal: for QuickBooks, two radio dispositions — Disconnect (default; today's behaviour, revivable on re-OAuth) and Sever and go native (keep the chart QuickBooks created as the graph's own; QuickBooks can never resume; bank feeds connect after). Every other provider keeps the single confirmation. The dialog names the provider fromPROVIDER_LABELS(now exported fromConnectionCard) instead of the raw slug.content.tsx:handleDeleteConnection(disposition)passesquery: { disposition }toSDK.deleteConnection; the success toast says which happened.Tests
ChartTemplatePicker.test.tsx(5): listing and default selection, initialize with template + legal form, null legal form when the entity's own is kept, the 409 refusal, a load failure.DeleteConnectionModal.test.tsx(4): QuickBooks defaults to disconnect, sever once chosen, single disposition for other providers, hidden renders nothing.Dependency:
@robosystems/client^1.15.0 → ^1.16.0 (package.json, lockfile).Deploy Notes
mainbut the latest release is v1.11.18 (2026-09-09), which predates them. Deploy the API first: until then the picker'schartTemplatesquery errors andinitialize-chart-of-accountsreturns 404, anddisposition=severis ignored bydeleteConnection.@robosystems/client1.16.0: additive (two new facade methods, one new optional query parameter); no existing call site changed shape.Testing
npm run test:all(vitest, format, lint:fix, typecheck, cf-lint): 409 tests passed across 55 files; ESLint, tsc and cfn-lint clean. The pre-commit gate ran the same.🤖 Generated with Claude Code
https://claude.ai/code/session_0188CbjDiNBtxdEYjSJ5Y7mX