c0ecf2fa3bebd46bdfd0169efd73b89653d1dfed
26 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f1230282a9 |
feat(bookkeeping): verifikationsserie per bankkonto for bank-transaction bookings (#2160)
* feat(bookkeeping): verifikationsserie per bankkonto for bank-transaction bookings A company running several bank accounts (main bank on A, company card on M, both imported via CSV) could not route each account's bookings into its own series: every bank_transaction booking took the single company-wide default from default_voucher_series_per_source_type. - cash_accounts.voucher_series (nullable, single letter): per-account override, editable under Inställningar → Bokföring → Verifikationsserier per bankkonto (new PATCH /api/cash-accounts/[id]). - resolveCashAccountVoucherSeries(): step 2 of the resolution order (explicit pick → account override → per-type map → A). Wired into the book route and createTransactionJournalEntry, which covers categorize, the agent, pending operations and the v1 API. - Booking dialog gets the series picker, seeded from the server via /voucher-sequences/next?source_type&cash_account_id so dialog and route can never disagree. An unresolved embedded picker omits voucher_series so a stray 'A' never overrides the account's series. Scope: bank_transaction bookings only. Invoice settlements matched from the bank keep their payment series; bulk-book resolves inside its RPC (see DECISIONS.md). Migration applied to staging as 20260902121420. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWSLbQc3jgpfqnxWe6nteh * fix(bookkeeping): audit and document the per-bankkonto series, tighten preview and PATCH Consolidated pass over the PR #2160 findings (skeptics, CodeRabbit, Swedish compliance review): - Behandlingshistorik (BFNAR 2013:2 p. 9.16): changing cash_accounts.voucher_series is a behandlingsregel that outranks the audited per-type map. New trigger audit_cash_accounts_voucher_series (UPDATE only, WHEN the series changes, so bank-sync churn never logs), cash_accounts added to AUDITED_TABLES and the audit_log filter, "Bankkonto ... Verifikationsserie: (tomt) -> M" events in the report, pg-real test. Applied to staging as 20260902124513. - Systemdokumentation (p. 9.2-9.15): revision/systemdokumentation.json gains a verifikationsserier_regler block with the resolution order and the two exceptions (invoice settlements, samlingsverifikat); the per-account mapping itself is in data/cash_accounts.json. - Settings picker uses the same closed list as the manual verifikat form (presets plus letters already in use) instead of all 26 letters; strings moved to messages/sv.json and messages/en.json. - /voucher-sequences/next applies the account override only for source_type=bank_transaction (CodeRabbit), so a manual-entry preview cannot show a series the entry will not get. - Book route resolves the series from the account the row ends up on after a stranded-row repoint, not the stale one. - PATCH /api/cash-accounts/[id] answers 404 for a non-UUID id instead of a Postgres cast 500; the series lookup logs a warning when it fails open. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWSLbQc3jgpfqnxWe6nteh --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
c981384a0e |
fix(transactions): keep the assistant usable through the whole booking flow (#1975)
* fix(transactions): keep the assistant usable through the whole booking flow Three gaps around the agent sheet during booking on Transaktioner: - The AgentTrigger bubble lived inside #dash-shell, so the inert that non-modal dialogs set on the shell made the assistant impossible to OPEN once a booking dialog was up. Moved outside the shell (it is position: fixed) and raised to z-[45]: above the DialogVeil (z-40) so it stays clickable, below dialog content (z-50). Under true modal dialogs Radix's body pointer-events lock keeps it dead as before. - Wide dialogs centered on the full viewport while the docked sheet (z-60) covered their right edge, hiding e.g. the Granska button. DialogContent now centers in the space left of --agent-dock-w, and the wide booking/review variants cap their width against it. - Step 1 of the flow (template picker, QuickReviewDialog) was still fully modal, so the assistant was dead there. Both are now non-modal with DialogVeil + a shared ref-counted useDashShellInert hook (also replacing the duplicated inert effects in TransactionBookingDialog and NewInvoiceDialog). Their Esc/veil-click dismissal is kept: they hold no half-filled form. Clicks in the agent sheet or its trigger never dismiss any dialog: data-agent-ui counts as inside, same mechanism as data-dialog-companion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): dialog centering reads a docked-only sheet width variable Skeptic review refuted the first cut: globals.css seeds --agent-dock-w at the 10px frame gutter on :root by design, so the 0px fallback in the new dialog centering never applied and every dialog sat 5px left of center (full-bleed dialogs clipped 5px off-screen). Introduce --agent-sheet-w, set inline by AgentSheetProvider only while the sheet is docked and removed otherwise, so the 0px fallback is real: sheet closed or floating renders byte-identical to the old left-[50%] and old max widths. Also cap the template picker and QuickReview's narrow variant, which could clip off-screen left on narrow desktops with the sheet docked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
98aff7c577 |
fix(transactions): keep booking dialog open while typing in the agent sheet (#1966)
* fix(transactions): keep booking dialog open while typing in the agent sheet
TransactionBookingDialog was a default modal Radix dialog; the agent
sheet is a fixed z-[60] panel portaled outside its DOM, so a click in
the assistant's text field counted as an outside interaction and
dismissed the dialog, losing the half-filled booking.
Apply the established non-modal convention (NewInvoiceDialog /
NewJournalEntryDialog): modal={false} + DialogVeil, with escape and
outside-dismiss prevented. Closing is explicit via the header X.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(transactions): restore page modality via inert while booking dialog is open
Skeptic review caught that the non-modal convention was ported
incompletely: NewInvoiceDialog pairs modal={false} with an inert effect
on #dash-shell. Without it the background page stayed keyboard-, AT-,
and (mobile nav) tap-reachable behind the veil, so a stray Shift+Tab
plus Enter could navigate away and destroy a half-filled booking.
Also corrects the comment that cited NewJournalEntryDialog as non-modal
precedent (it is plain modal).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
567fae654c |
perf(bookkeeping): booking dialogs render populated on open from the session cache (#1935)
The bookkeeping dialogs were the customer's "fields load late" in its purest form: Bokför (TransactionBookingDialog + the embedded JournalEntryForm) issued five requests on every open (fiscal periods, accounts, settings, cash accounts, then the voucher preview once the first two had landed), Nytt verifikat the same minus one, BookDirectlyDialog four, and the template dialogs two. Each Radix dialog unmounts on close, so every reopen paid the full price again, and several fields visibly flipped: the bank line seeded '1930' then rewrote itself, the series defaulted to 'A' until settings arrived, the period select was empty. All of them now read lib/reference-data (seeded by the dashboard layout): - JournalEntryForm: periods, accounts and settings from the hooks; dimensionsEnabled derived, not fetched; the voucher-number preview is keyed on the entry date (the route resolves the period from it) so it fires as soon as the series is known instead of after the period fetch; after activating accounts it invalidates the shared accounts cache; the create-period dialog callback invalidates the periods cache. - TransactionBookingDialog: settlement account and its name derived with useMemo from the cached cash accounts; the form mounts on the first paint. - BookDirectlyDialog: cash accounts, periods and accounts from the hooks; the '1930'-then-rewrite disappears because the resolved account is known on the first render. - TemplateBookDialog, BookingTemplatePicker, TemplatePicker: templates (and periods) from the hooks. - BookingTemplatesPanel (delete, import) and CreatePeriodDialog (create) invalidate the corresponding cache entries so every picker sees the change at once. - fetchers.ts: booking templates are booking_templates rows (BookingTemplateLibrary), not the static BookingTemplate shape. Per open: Bokför 5 requests -> 0 blocking (voucher preview is a non-blocking hint), Nytt verifikat 5 -> 1 non-blocking, BookDirectly 4 -> 0, Mall 2 -> 0, template pickers 1 -> 0. raw-reference-fetch ratchet: 51 -> 46 files. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0bb482bf6e |
feat(bookkeeping): edit the lines of a proposed kontering (Andra rader) (#1894)
* feat(bookkeeping): edit the lines of a proposed kontering via Andra rader Proposal views (AI suggestion, static template, counterparty template with or without a line pattern) previously offered only accept-or-start-over: the verifikation preview was pure rendering and the only line-editable path was library templates. This adds an "Andra rader" affordance to the proposal view in QuickReviewDialog that hands the COMPUTED lines (accounts, SEK amounts, VAT legs, exactly what the preview shows) into TransactionBookingDialog / JournalEntryForm as an editable prefill, reusing the same initialLines mechanism library templates already use. - lib/bookkeeping/proposal-lines.ts: line computation extracted from JournalEntryPreview into computeProposalLines() (single source for preview and prefill, so they cannot drift) plus proposalLinesToFormLines() mapping to the JournalEntryForm prefill shape. The settlement leg is flagged so the booking dialog swaps in the transaction's resolved cash account and stamps currency metadata, mirroring buildInitialLinesFromTemplate. - JournalEntryPreview now renders computeProposalLines() output unchanged. - TransactionBookingDialog accepts proposalLines (takes precedence over preselectedTemplate); the booking still goes through JournalEntryForm's normal manual validation and the engine, no validation bypassed. - Ore rounding funnels through roundOre(); guard baseline ratcheted down. - New strings in messages/sv.json and messages/en.json (tx_quick_review). - Unit tests for all three proposal branches incl. VAT legs, reverse charge, multi-line patterns, 3740 rounding diff and FX metadata. Fixes #1878 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(bookkeeping): make the Andra rader prefill engine-exact (skeptic findings) Three skeptics refuted the first cut of #1878: the extracted preview math was a lossy approximation of the engine, and making it bookable made every loss a real booking defect. This commit closes each refuted scenario by mirroring the exact engine path per proposal branch: - Balance: VAT is single-rounded and the net leg is gross minus that VAT (transaction-entries.ts semantics). Independently rounded net+VAT went off by 1 ore for 12% grosses at 14 mod 28 ore (e.g. 102.06, 100.94), prefillling an unbookable verifikat. - 'Ingen moms' deviation: the dialog resolves the UI 'none' sentinel via resolveExplicitVat before computing lines, so an explicit no-VAT choice prefills no VAT line instead of re-deriving the 25% category default into a bookable 2641 leg (ruta 48 inflation on e.g. loan repayments). - Ore parity: engineRound (plain Math.round(x*100)/100, matching the engine) replaces roundOre where the engine is naive; roundOre kept only where the engine uses it (category VAT leg). No more 1-ore drift between preview, prefill and the booked verifikat (8.62 RC, 34.30@12%). - Legacy counterparty pairs: new counterpartyLegacy mode mirrors the legacy booking path: reverse charge emits the 2645/2614 fiktiv-moms pair (previously dropped: an RC expense would have booked without fiktiv moms, understating rutor 30/48), VAT on expenses only, income gross, and sign-mismatched matches mirrored like buildLegacyMismatchResult. - Pattern mirror: sign-mismatched line patterns flip learned sides like buildMultiLineMappingResult; ratio allocation filters business/tax types. - Entity accounts: static template accounts resolve debit/credit_account_ab for aktiebolag (resolveTemplateAccountsForEntity), so an AB no longer previews or books EF-only accounts like 2013. - Settlement swap: only a literal-1930 settlement leg is swapped to the resolved cash account (applySettlementAccount parity); learned non-1930 money legs (1510/2440/2890/19xx) stay authoritative. - FX: QuickReviewDialog hands its enriched transaction row to the booking dialog so the settlement leg's exchange_rate metadata matches the rate the SEK amounts were computed with. 34 unit tests incl. every skeptic counterexample; guard baseline ratcheted to 622 (below main's 626). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(bookkeeping): line-pattern settlement leg uses the learned legacy pair (skeptic refutation) Two independent skeptics refuted the pattern branch: the engine books the money leg on the counterparty template's learned legacy account (credit for an expense, debit for an income, mirror-swapped, falling back to 1930), while the preview/prefill defaulted to 1930. A SIE-learned pattern settling on 2440 showed kredit 1930 in the preview but booked kredit 2440 on confirm. QuickReviewDialog now passes the learned pair raw (no entity resolution, engine parity) and computeProposalLines selects the settlement account exactly like buildTransactionEntryLines; the literal-1930 swap to the resolved cash account is unchanged. CodeRabbit findings declined deliberately (see DECISIONS.md): the 3740 rounding line keeps the engine's business-side placement for both diff signs (parity contract; an unbalanced set is rejected at commit), and the naiveOreRound baseline stays at 622 (engineRound is a documented parity exception). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
cd46d936f3 |
fix(bokforing): account search results in the booking dialog search field (#1877) (#1889)
* fix(bokforing): account search results in the booking dialog search field (#1877) The search field in the "Bokfor transaktion" dialog only matched template metadata, so typing an account number or name (e.g. active 5460 Forbrukningsmaterial) gave zero hits and no path to booking; the real account search was only reachable via the discreet "Bokfor manuellt" link. - TemplatePicker now also searches the company's active chart of accounts (reusing lib/bookkeeping/account-search.ts) and shows hits as a "Konton" result group; picking one routes into the same manual booking flow as "Bokfor manuellt" with the account prefilled on the counter line. - New buildActiveAccountIndex helper indexes chart rows active-only, so deactivated accounts never surface as bookable results. - searchTemplates additionally prefix-matches all-digit tokens against a template's business account (debit for expense, credit for income, both legs for transfers, AB variants included); the settlement leg is deliberately excluded so "1930" does not light up every template. - Library template search prefix-matches line accounts on all-digit queries. - Empty search results show a hint pointing at "Bokfor manuellt" for accounts outside the active chart; placeholder now says "Sok mall eller konto...". New strings in both messages/sv.json and messages/en.json. Fixes #1877 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(bokforing): match only business lines when digit-searching library templates (#1877) CodeRabbit review on PR #1889: the all-digit library-template match also hit settlement and VAT lines, so searching "1930" lit up every user template with a bank settlement leg. Restrict the predicate to business lines, mirroring the static catalog's settlement-leg exclusion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4dbd19aeb0 |
fix(transactions): the underlag column is one surface, not a dropzone and an orphan button (#1628)
* fix(transactions): the underlag column is one surface, not a dropzone and an orphan button
The Bokfor transaktion dialog stretched its empty dropzone into a
45/72vh well and pinned "Valj befintligt underlag" alone at the very
bottom of the column, visually disconnected from the dropzone it
belongs to.
- Empty state: the underlag column now sizes to its content and
top-aligns; the inbox picker renders as a quiet full-width dashed
row directly under the dropzone ("eller valj befintligt underlag
fran inkorgen"), so drop-a-file and pick-from-inbox read as one
intake surface. The fixed-height sticky column returns as soon as
a document previews there (uploaded, picked, or pre-linked).
- Grid rebalanced from 1fr/520px to 2fr/3fr so the kontering side
dominates while nothing is being previewed on the left.
- QuickReviewDialog gets the same footer-row treatment for its picker
trigger inside the underlag collapsible, so both #1620 surfaces
present the affordance identically (disabled-while-booking kept).
Presentation only: upload path, select-mode picker held until booking,
linkDocuments with inbox_item_id, picked-state resets on close and
transaction change, and duplicate-match wiring are all unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: record the QuickReviewDialog picker-trigger consistency decision
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
9686b54b41 |
refactor(design): lock the border-radius ladder, one radius per role (#1607)
Seven radii were in circulation (4/5/6/8/12/16px + pill) with no rule for which went where; one toolbar row on /transactions mixed four shape languages. This locks a 4-tier ladder (design.md convention 16): - pill: interactive toolbar controls (buttons, chips, pickers, segmented controls, toolbar search, count nubs) - rounded-xl (12px): overlay tier: page panel, dialogs, slide-overs - rounded-lg (8px): cards, form fields, popover/menu content, boxes - rounded-sm (4px): nested leaves (menu items, checkboxes, kbd/code nubs) Changes: - New SegmentedControl primitive (pill-in-pill tablist, h-8) replaces the hand-rolled bg-muted/70 tablist copied across 11 files - New ToolbarSearch primitive (pill, h-8) adopted on 9 page toolbars; dialog/picker searches keep the rounded-lg Input - dialog.tsx 8px -> 12px, matching SettingsModal/slide-over/CommandPalette - ContextPicker chips at the shared h-8 toolbar height - ~300 rounded-md / bare rounded call sites remapped by role; auth icon tiles and the mobile nav sheet come down from 16px to 12px - rounded-md, bare rounded, rounded-2xl and rounded-[Npx] are dead vocabulary, enforced by a new off-ladder-radius check in check:guards Verified: lint 0 errors, 14422 unit tests pass, check:guards green, tsc clean on all changed files, sandbox screenshots of transactions/ bookkeeping/granskning toolbars and the Ny verifikation dialog. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
da859d7236 |
refactor(ui): design-system consistency pass over dense pages + i18n de-bloat (#961)
* refactor(ui): normalize dense pages to the locked design system Sweep of the info-dense surfaces against .claude/rules/design.md; no behavior changes, classNames and primitive adoption only. - Replace hand-rolled h1s with PageHeader (import, suppliers, kpi, salary/employees, skattekonto, settings layout) and drop the one double title (SalarySettingsContent under the settings h1) - Replace hand-rolled empty states with EmptyState (skattekonto, banking/api-keys/oauth/counterparty settings) and hand-rolled pulse divs with Skeleton (deadlines, report view loaders) - Remove semantic colors used as chrome: amber/emerald banners in AGIPanel and SkatteverketPanel, success/warning tints in kassaflodesanalys, arsredovisning and import become neutral surfaces with the tint kept on the icon only - Full-opacity borders everywhere (border-border/30-60, border-destructive/20-40, border-foreground/30, text-destructive/80) - Snap off-scale spacing (p-5 to p-6, p-2.5 to p-3, gap/mt-x.5 to scale values); KPI metric tiles p-6 to p-4 per the tile rule - Remove the mobile Select that duplicated the invoices status Tabs (TabsList already scrolls horizontally); single Tabs now serves both breakpoints - supplier-invoices: shared formatCurrency instead of a local formatAmount helper; skattekonto: formatDate/formatDateLong/ formatDateTime instead of raw dates and toLocaleString - arsredovisning flerarsoversikt converted to the Table primitive with right-aligned tabular-nums cells - Settings: CardTitle text-base on section cards, one heading idiom in AccountSettingsContent, h3 to h2 in CompanyProfileView Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(i18n): trim text bloat and fix an untranslated sv string - Fix invoice_credit.create_failed_fallback: sv catalog carried the English "Failed to create credit note"; now "Kunde inte skapa kreditfaktura". Translate new_user_checklist.step3_title in en - Drop descriptions that paraphrase their own title (design.md forbidden pattern): invoice_detail.credited_description, invoice_credit.original_card_description, invoice_editor customer/notes card descriptions (keys deleted from both catalogs, zero remaining usages); the transaction booking DialogDescription becomes sr-only so screen readers keep it - Trim redundant sentences from settings_salary.info_payroll_scope, settings_backup.intro, ext_cloud_backup_long_description, settings.name_description, salary_payments.open_payments_note and shorten invoice_credit.reason_card_description; statutory BFL/tax prose untouched - Normalize toast punctuation (dimensions/self_billing created_description lose the trailing period like their siblings) - common.delete "Radera" to "Ta bort" (zero live call sites; Radera stays reserved for irreversible account/company deletion) Catalogs verified key-identical (4795 keys each) and JSON-parseable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
82c66739d7 |
fix(transactions): steer duplicate guard to matching for ledger-only vouchers (#958)
When the booking-time duplicate guard flags a ledger-only voucher candidate (transaction_id null: a verifikat from an SIE import, a paid invoice, a salary payout), the dialog's primary action is now "Matcha mot verifikatet": it links the bank transaction to the existing voucher via /api/reconciliation/bank/link (the same path MatchVoucherDialog uses) instead of double-booking the same affarshandelse. "Bokfor anda" stays available but demoted to an outline button. Sibling-transaction candidates keep today's layout: matching a second bank line onto a voucher that already has one is the N:1 edge case, not the default. Wired through both call sites: the transactions page (runCategorize) reuses handleVoucherLinked's refresh, and TransactionBookingDialog (JournalEntryForm, /api/transactions/[id]/book path) reuses the booked flow so in-dialog attached documents land on the matched verifikat and the row leaves the list, with a "Bankhandelsen kopplad" toast instead of "Bokford". No lib change: the candidate payload already carries the transaction_id discriminator, covered by existing detection tests. Closes #919. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5149caebbf |
fix(transactions): use the resolved cash account name as bank line description (#899)
The booking dialog's bank line description was always the generic "bank_line_description" translation regardless of which cash account was actually resolved via resolveAccount(). This was accurate while the bank line was hardcoded to 1930, but now that the dialog resolves the real cash_account_id (#769) it can pick a different account whose own name should show up on the line instead. Signed-off-by: Jonas Flodén <jonas@floden.nu> |
||
|
|
ec27228a8e |
style: remove em/en dashes repo-wide, add CLAUDE.md rule against them (#890)
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> |
||
|
|
f63d3e3100 |
Bug/open banking flow (#854)
* fix(enable-banking): pin Mobile BankID (decoupled) auth_method so Handelsbanken corporate connects We never sent auth_method to Enable Banking, so it fell back to the ASPSP's visible default — REDIRECT for Handelsbanken. For Handelsbanken *corporate* PSUs the redirect flow does not support Mobile BankID, so authorization failed right after the user approved in the BankID app. Mobile BankID at Handelsbanken is a DECOUPLED method flagged hidden_method=true, which Enable Banking only uses when requested explicitly. Resolve the bank's preferred auth method before /auth: query the ASPSP's auth_methods and pick the DECOUPLED (Mobile BankID) method when present, otherwise leave auth_method unset so banks that already work are untouched. The method name is read dynamically per psu_type, so it is robust across sandbox/production naming. - api-client: add approach/hidden_method to AuthMethod, fix ASPSP.auth_methods field name (was available_auth_methods, never populated), add getPreferredAuthMethod(), thread optional authMethod through startAuthorization - index: resolve authMethod in /connect and pass it on both fresh + reconnect - tests: cover method selection and request-body shaping Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(invoice-inbox): clean up bulk-selection toolbar UI Redesign the selection toolbar shown when inbox items are checked: one solid primary "Bokför valda" button with outlined secondary actions ("Fråga assistenten", "Ta bort") and a plain selection count. Removes the redundant "Avmarkera" button (users uncheck the still-visible box), fixes label clipping, and gives the toolbar more breathing room. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(entitlements): bypass paywall in local development Add isPaywallBypassed() so all gated capabilities are testable locally without a subscription. Fires only on NODE_ENV=development (npm run dev) or an explicit DISABLE_PAYWALL=true escape hatch — production builds run under NODE_ENV=production and the entitlement suite runs under 'test', so both keep exercising the real gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tic): resolve enskild firma bolagsuppgifter via 12-digit personnummer TIC's Lens search is fuzzy and only resolves an enskild firma from the 12-digit (century-prefixed) personnummer; a 10-digit form fuzzy-matched an unrelated entity. Expand personnummer to 12 digits before querying and reject hits whose registration number is unrelated to the request. Add a "Hämta" action to the settings Bolagsuppgifter panel to (re)fetch on demand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(transactions): implement categorize core for bank transaction categorization - Added `categorize-core.ts` to handle categorization of bank transactions, supporting single and bulk operations. - Introduced `categorizeMatchedTransaction` and `bulkBookMatchedInboxItems` functions for transaction processing. - Implemented fiscal period validation and duplicate booking detection. - Enhanced logging and error handling for transaction categorization. feat(scripts): add diagnostic script for Handelsbanken ASPSP metadata - Created `check-handelsbanken-aspsp.mjs` to fetch and display available authentication methods for Handelsbanken. - Outputs metadata for business and personal PSU types, including default authentication methods. fix(migrations): increase statement timeout for SIE bulk delete operations - Updated `20260629160000_sie_bulk_delete_statement_timeout.sql` to set a longer statement timeout for bulk delete RPCs to prevent cancellations during large imports. feat(migrations): add bulk book inbox items to pending operations - Expanded `pending_operations` table to include `bulk_book_inbox_items` operation type in `20260630120000_pending_operations_add_bulk_book_inbox_items.sql`. - Supports bulk booking of matched inbox items against bank transactions. test(pg): add tests for replace_period_opening_balance_link RPC - Implemented tests in `replace-period-opening-balance-link.pg.test.ts` to validate the functionality of the opening-balance correction flow. - Ensured immutability of opening balance links and proper handling of posted vs. non-posted entries. * fix(sie-export): update journal entries and lines handling in SIE export tests * fix(migrations): resolve version collision on 20260629160000 The SIE bulk-delete statement_timeout migration shared version 20260629160000 with journal_entries_list_series_filter (merged from main via #798/#823), causing a schema_migrations_pkey duplicate key error on apply. Rename the branch's migration to 20260629160100. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(compliance): resolve compliance-swarm + review findings - opening-balance/correct: compensating rollback for the non-atomic storno+rebook so a mid-sequence failure never leaves two posted OB entries (ASVS V2.3); durable audit event on every failure path (V16); reference the original verifikationsnummer in the corrected entry per BFL 5 kap 5§; document that requireWrite already enforces write-role + membership (V8.2.1 was a false positive) - reports sources routes: validate the cursor date component as ISO (/^\d{4}-\d{2}-\d{2}$/) before use, 400 on malformed (ASVS V1.2), applied to both the VAT-declaration and trial-balance routes - AgentSessionList: await the rename PATCH, revert the optimistic title and toast on failure (ASVS V4.5) - bank booking: exclude same-batch siblings from the booking-time duplicate guard so bulk-booking distinct same-(date,amount) transactions no longer false-positives; pre-existing duplicate detection is preserved - BulkBookInboxDialog: drop the unsafe currency-based reverse_charge default, add an omvänd skattskyldighet advisory, and type VAT options to the backend VatTreatment union - OpeningBalanceRowEditor: hold onChange in a ref (synced in effect, not during render) so an unstable callback can't cause a render loop Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1cd8863958 |
fix(transactions): resolve bank account from cash_account_id in booking dialog (#769)
* feat(transactions): expose cash_account_id in list API response Add cash_account_id to the transactions list API select so that components can resolve the bank account from the transaction instead of hardcoding. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Jonas Flodén <jonas@floden.nu> * feat(cash-accounts): extract resolveAccount to shared utility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Jonas Flodén <jonas@floden.nu> * refactor(transactions): use shared resolveAccount in MatchVoucherDialog Replace the local resolveAccount function with the shared utility from lib/cash-accounts/resolve-account, reducing code duplication and improving maintainability. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Jonas Flodén <jonas@floden.nu> * fix(transactions): resolve bank account from cash_account_id in booking dialog Replaces the hardcoded '1930' bank leg in TransactionBookingDialog with the actual ledger_account of the transaction's cash account. Companies with multiple bank accounts (e.g. 1930 + 1940) now get the correct account pre-filled in both the blank and template-based booking flows. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Jonas Flodén <jonas@floden.nu> * fix(transactions): cancel stale cash-account fetch on dialog re-open Signed-off-by: Jonas Flodén <jonas@floden.nu> * fix(transactions): prevent form remount discarding edits during bank account fetch Hold JournalEntryForm render until the /api/cash-accounts fetch resolves by changing bankAccount state to string | null (null = pending). This prevents the form from mounting with key '…-1930', then immediately remounting with the correct account key and losing any user edits made in the sub-100ms window. Also adds r.ok guard before parsing and sets '1930' as explicit catch fallback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Jonas Flodén <jonas@floden.nu> * fix(transactions): cancel stale cash-account fetch in MatchVoucherDialog Pass a signal object into loadCandidates and return a cleanup from the useEffect so a stale in-flight fetch (from a previous transaction) cannot call setAccountNumber/setAccountFallback/setGlLines/setSelected after the dialog re-opens for a different transaction. Also adds r.ok check before parsing /api/cash-accounts response. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Jonas Flodén <jonas@floden.nu> --------- Signed-off-by: Jonas Flodén <jonas@floden.nu> |
||
|
|
36e3f6ceb0 |
Design critique: normalize daily-operator flows + UX improvements (#741)
* style(design): normalize daily-operator flows to locked design system Sweep the dashboard, transactions, reconciliation, invoicing and supplier flows for design-system violations (.claude/rules/design.md): - font-medium removed from Hedvig display headings/numerals - font-mono -> tabular-nums on monetary values (voucher ids stay mono) - raw Tailwind status colors -> Badge variants / muted-alert pattern - semantic colors removed from chrome backgrounds (deadline widgets, icon halos) - hand-rolled skeletons/empty-states -> Skeleton / EmptyState primitives - opacity-suffixed borders, the invisible warning-foreground count color, and shadow-sm/rounded-xl on non-overlay surfaces normalized The four files that also received UX changes carry their token fixes in the following commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(ux): clearer dashboard CTA, match confidence, AI provenance, invoice actions Four high-impact UX fixes from the design critique (these files also carry their design-system token normalization): - Dashboard: render the next-best-action hero for every agent-built company, not only 'slim' nav density, so there is always one obvious next step instead of four equal-weight metric tiles. - Reconciliation: surface the match engine's 0-1 confidence as a graded strength badge (Stark / Trolig / Svag traff) in the shared verifikat picker rows and selected chip; drop the uninformative binary "Foreslagen traff" badge from the match dialog. - Supplier inbox: show AI-filled provenance per extracted field (a success dot that clears once the user verifies/edits the value) so misparsed amounts/dates get proofread before they post to an immutable verifikat. - Invoice detail: keep each status's primary action only in the header row; the sidebar "Status actions" card now holds secondary/reversible actions only (makulera, ta bort, skapa kreditnota, manual-send alternative), removing the duplicated CTAs and closing a viewer-permission gap on the old sidebar buttons. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(ux): Tier-B medium design-critique fixes across daily-operator flows - Reconciliation: standardise the match-confirm verb on "Matcha" (was "Koppla" in MatchVoucherDialog) and replace the hand-rolled date <input>s in the bank reconciliation view with the Input primitive. - Supplier inbox: fold the two alternative bookings (Skapa leverantorsfaktura / Bokfor som verifikat) behind a single "Andra satt att bokfora" dropdown so the default path (Matcha mot transaktion) stays the lone primary action. - Duplicate-payment guard: demote the "Skapa ny verifikation anda" escape hatch to a ghost button so the safe "Koppla till befintlig" path dominates. - Onboarding: raise the "start fresh" escape hatch from a muted text link to a visible secondary button; normalise the checklist's off-scale spacing. - Supplier flows: finish the font-mono -> tabular-nums sweep on monetary values in the supplier-invoice detail / create / review surfaces (ids stay mono). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(deadlines): keep overdue rows visually distinct (destructive chrome is allowed) The Tier-A normalization stripped all semantic-color row tints from the deadline widgets, but design.md exempts --destructive ("only --destructive survives in chrome"). Restore a subtle bg-destructive/5 on OVERDUE rows so missed tax/AGI deadlines (-> skattetillagg) stay noticeable in a list scan; action-needed (warning) rows stay clean since warning is data-only. Surfaced by the Swedish compliance review on #741. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reconciliation): hide match-strength badge on already-matched verifikat Per the Swedish compliance review on #741: a green "Stark traff" confidence badge rendered alongside "Redan matchad" could visually nudge an accidental double-match of a posted verifikat (a BFL 5 kap audit-trail concern). Suppress the strength badge when linked_transaction_count > 0 so "Redan matchad" is the lone signal there; N:1 matching stays an explicit opt-in. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0521c385d2 |
feat(transactions): underlag status badges + attach dialog; auto-expire stale pending ops (#712)
* feat(transactions): per-row underlag status + attach-document dialog
- New "Matcha mot underlag" dialog on /transactions (inbox pick or fresh
upload), the tx→doc mirror of the Documents view's matcher
- Per-row Underlag/Underlag saknas badges on booked history rows, driven
by computeJeUnderlagStatus — same posted-only, exemption-aware scope as
the worklist count so badge and count never disagree
- attach-document route + commit dispatcher now propagate the doc onto
the verifikation when the tx is already booked (BFL 5 kap 6 §), with a
409 guard for docs consumed by a different verifikation, idempotent
re-attach (no same-value rewrite under period lock), and an honest 409
when the period-lock trigger blocks the propagation
- Booking-dialog doc links also pin the doc to the transaction row
(first linked doc wins) via the link route's new transaction_id param
messages/{sv,en}.json also carries the strings for the pending-ops
expiry UI that lands in the next commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(pending-operations): auto-expire stale staged operations after 30 days
- New daily cron (02:30 UTC, vercel.json + both docker crontabs) flips
>30-day-old pending ops to rejected with the dispatcher's
{ auto_rejected: true, reason: 'expired' } result_data shape — rows are
never deleted, the table is the audit trail
- /pending renders an "Utgick automatiskt" badge + detail line for these,
orders terminal tabs by resolved_at so a fresh expiry sweep isn't
buried, and adds a first-time-reviewer explainer
- Origin labels spell out where a proposal came from (AI chat, MCP key,
API, cron) instead of the raw actor_label
- agent_chat actor type added to PendingOperationActorType/AuditLogEntry
(DB CHECK already widened in 20260519090000) and to the agent filter
- ApprovalCard notes that ignoring a proposal is safe
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(mcp): surface the client telemetry marker in connect instructions
Tag the connector URLs shown in ApiKeysPanel, the connect-claude doc and
the gnubok-mcp README with ?client=<surface> (claude-connector /
claude-code) and GNUBOK_CLIENT=claude-desktop for the npm bridge.
Telemetry-only — the server already reads the param/header; this just
lets us measure which Claude surface connected.
The claude mcp add copy blocks quote the URL: an unquoted ? in the query
string trips zsh globbing ("no matches found").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* review: fix stale-closure badge flip + zod-validate link route body (PR #712)
- handleDocumentAttached read journal_entry_id off the render-time
transactions snapshot; if the list changed while the attach dialog was
open the optimistic badge flip was silently skipped. Read it off the
dialog's own subject (attachDocTx) instead.
- POST /api/documents/[id]/link now validates the body against the new
LinkDocumentSchema (uuid-strict, all four fields) instead of a bare
presence check on journal_entry_id — same canonical VALIDATION_ERROR
envelope. Test fixtures switched to real UUIDs accordingly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
cac692e293 |
fix(ux): book documents directly from inbox + attach existing underlag when booking transactions (#670)
* fix(inbox): re-add Bokför manuellt on unmatched documents Pilot feedback: a document in Dokumentinkorg could not be booked without first matching it to a bank transaction, which is impossible for cash expenses and other entries with no bank movement. The backend (/items/:id/book-direct) and BookDirectlyDialog already support standalone booking — re-expose the button in the unmatched state. The dialog still offers optional transaction selection inside. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(transactions): pick existing inbox document when booking manually Pilot feedback: "Bokför manuellt" from a transaction only allowed uploading new files — an already-uploaded underlag from the inbox could not be attached. Add a select mode to InboxDocumentPicker (onSelect prop; journalEntryId now optional) and mount it in TransactionBookingDialog: picked documents are linked after the journal entry is created via /api/documents/{id}/link with inbox_item_id, which also stamps the inbox item as consumed so it drops out of every pending surface. Non-ok link responses now count toward the failure toast (previously only network errors did). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(documents): address PR #670 review — stale preview dialog, JE tenancy check Review findings: - InboxDocumentPicker left the preview dialog floating open when a pick was confirmed from inside it (previewItem was never cleared before onClose; the component stays mounted, so the on-open reset never ran). Clear it in both select and link mode. (greptile) - linkToJournalEntry verified the document's company but trusted the client-supplied journal_entry_id (FK only requires existence). Add an explicit company-scoped journal entry lookup; misses map to the existing DOC_LINK_ENTRY_NOT_FOUND envelope. RLS prevented any data leak either way — this makes the rejection explicit. New regression test covers the cross-tenant case. (compliance-swarm A.8.28) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a586cc8a58 |
feat(transactions): show all library templates in picker; fix PSD2 seed-row collision (#596)
* feat(transactions): show all library templates in picker; fix PSD2 seed-row collision - Booking template picker: surface every active library template, not only the convertible 2-account shapes. Multi-leg/complex templates route to the manual journal editor pre-filled via applyTemplate instead of being hidden. Drop direction filtering for user templates (inferred direction is unreliable); the curated static catalog still respects it. Add an "Aktivera och bokfor" recovery toast for TX_CATEGORIZE_INVALID_ACCOUNT mirroring the existing ACCOUNTS_NOT_IN_CHART flow. CreateTemplateForm reflows to one card per line so trash buttons stop colliding on narrow screens. - cash_accounts.upsertFromPsd2: the seed_default_cash_account migration plants a manual (bank_connection_id IS NULL) row on the same ledger_account, so the first PSD2 sync's upsert on (company_id, bank_connection_id, external_uid) cannot match it (NULL != NULL) and falls through to INSERT, tripping the (company_id, ledger_account) UNIQUE constraint. Look up and promote the seed row in place first. - Tests: pin the TX_CATEGORIZE_INVALID_ACCOUNT error shape the recovery toast parses; cover applyTemplate on shapes the converter rejects (split-expense and all-'business'-typed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(transactions): PR review — currency metadata, MRU ordering, observable promote, BAS validation - TransactionBookingDialog.buildInitialLinesFromTemplate: attach buildCurrencyMetadata to settlement lines for foreign-currency transactions so the journal entry retains the original currency, amount, and exchange_rate. Without this, non-SEK transactions routed through a non-convertible template were recorded in SEK only with no foreign-currency annotation. (Greptile #2) - TemplatePicker.handleSelectLibraryRaw: only bump the MRU after confirming the click will actually do something (i.e. converted OR a callback is wired). Future consumers that omit onPickLibraryTemplate would otherwise corrupt MRU ordering for templates the user never successfully applied. (Greptile #1) - cash_accounts.upsertFromPsd2 promote-seed: add .select('id') so a zero-row UPDATE is observable. If the seed row vanishes between the SELECT and UPDATE (concurrent ops), fall through to the normal upsert instead of silently returning success without persisting anything. (Greptile #3, compliance A.8.9) - transactions/page.tsx TX_CATEGORIZE_INVALID_ACCOUNT toast: validate accountNumber against /^\d{4}$/ before embedding in any fetch URL/body. Defense-in-depth against a malformed server error envelope. (compliance V8.2.1) - categorize route test: switch the not-in-chart fixture from '4535' (Inköp av varor från annat EU-land — reverse-charge) to '5420' (Programvaror) so the example doesn't imply a domestic override against an EU-reverse-charge account would be valid without its paired moms legs. (Swedish compliance review #3) Other review items deliberately not addressed in this PR: - Validate-on-save that every VAT-rated template has a 'vat' line — overrides existing CreateTemplateForm UX, separate PR. - vat_rate enum guard in applyTemplate — defensive; the editor dropdown only surfaces legal rates and is the only write path in production today. - Imbalance UI warning — already handled: JournalEntryForm computes isBalanced and gates submission; DB trigger check_journal_entry_balance enforces BFL 5 kap server-side. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e4488a900b |
feat: add user locale preference to user_preferences table (#555)
* feat: add user locale preference to user_preferences table
- Introduced a new column 'locale' in the user_preferences table to store per-user UI language preferences.
- Added a CHECK constraint to ensure only supported locales ('sv', 'en') are allowed.
- Triggered a schema reload notification for the changes.
chore: declare CSS module support in TypeScript
- Added a declaration for CSS modules in globals.d.ts to enable TypeScript support for importing CSS files.
* feat: add Swish as an invoice payment method in company settings
|
||
|
|
bb336eba88 |
Fix/user feedback (#210)
* Add delete policies for provider consent tokens and provider OTC * Add trade name support for companies in settings and documents * Resolved currency selection issue * Enhance invoice line display with foreign currency support and update delivery date schema to allow empty values * Add currency display for journal entries and include currency metadata in transaction creation * Add trade_name column to company_settings for external display |
||
|
|
a7be1aab17 |
feat: comprehensive UI design audit and normalization (#28)
* feat: import system improvements, INK2 fix, and Swedish text corrections - SIE parser: Windows-1252 and CP437 encoding detection and decoding - Bank file parser: add Nordea Business (Företag) CSV format - Bank file parser: improve format detection for SEB, Länsförsäkringar, generic CSV - INK2 engine: calculate årets resultat (7222) from income statement for open fiscal years - Dashboard: parallel Supabase queries, simplified dashboard page - Fix Swedish characters (å, ä, ö) in BAS data descriptions, validation messages, AI consent disclosures - Import wizard UI improvements across all steps - Migration: add 'bas_range' match type to sie_account_mappings constraint - Extensive new tests for SIE parser encoding and bank file parser Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: arcim migration wizard UX fixes, Sentry setup, and extension scaffolding Arcim migration wizard improvements: - Progress bar now excludes non-interactive steps (migrating/result) - Fix OAuth text to match target="_blank" behavior (new tab, not redirect) - Display month names instead of "Månad X" in preview - Fix Swedish typo "förifylla" in no-company-info message - Replace native checkboxes with shadcn Switch in options step - Add ConfirmationDialog before starting migration - Show progress percentage during migration - Add "Nästa steg" guidance and navigation links in result step - Add "Försök igen" button in error state (returns to options) - Add Bokio company ID help text (GUID from URL) - Add Fortnox integration add-on hint on connection failure Also includes: SIE import system improvements, INK2 fixes, Swedish text corrections, Sentry error tracking setup, and arcim-migration extension scaffolding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review feedback - Fix OAuth error recovery blank page (restore provider from URL params) - Pass real userId to MigrationWizard instead of empty string - Remove ~50 debug console.log statements from sie-import.ts - Fix comment referencing account 3740 → 3741 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: comprehensive UI design audit and normalization Dashboard audit: - Fix muted-foreground contrast (4.31:1 → 5.08:1) for WCAG AA - Add prefers-reduced-motion media query for all animations - Replace border-l-2 accent anti-pattern with subtle full-border colors - Add aria-expanded to toggle buttons, role="status" to live counters - Fix touch targets on deadline buttons (28px → 36px) - Vary section spacing for rhythm (mb-12/mb-10/mb-8) - Remove unused imports and dead code Transactions audit + hardening: - Add pagination (200 per page) with "Ladda fler" button - Replace height animation with transform-only exit animation - Show batch progress in floating action bar during processing - Fix batch bar mobile overlap (bottom-20 on mobile) - Replace clickable badges with proper button elements - Add safe area padding to fullscreen swipe view - Add response.ok check to suggestion fetch - Add truncation to invoice number buttons Invoicing audit: - Remove border-l-4 accent pattern from invoice cards - Replace string concatenation with cn() utility Systemic sweep (34 files): - All page headings: font-bold → font-display font-medium (Fraunces) - All stat numbers: font-bold → font-display font-medium tabular-nums - All hard-coded blue/amber/emerald colors → design tokens - Remove all dark mode overrides (tokens handle automatically) - Tint pure white card background to 99% Design context added to CLAUDE.md with brand personality, aesthetic direction, and 5 design principles. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: bookkeeping flow audit — design system, accessibility, UX - Replace raw <select> with shadcn Select component (JournalEntryForm) - Add confirmation dialog for account deletion (ChartOfAccountsManager) - Remove console.error from production code (JournalEntryList, JournalEntryForm) - Fix contradictory h-7/min-h-[44px] button sizing → h-10 (ChartOfAccountsManager) - Increase BAS catalog "Lägg till" touch target h-7 → h-9 - Improve loading state with spinner (JournalEntryList) - Improve empty state with icon, description, and guidance (JournalEntryList) - Add response.ok check on journal entry fetch - Add aria-expanded to entry expand buttons - Add tabular-nums to desktop debit/credit columns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: onboarding and empty state improvements Onboarding: - Replace font-serif with font-display (Fraunces) for brand consistency - Remove console.error calls from production code Empty states: - Fix broken /transactions/new link in EmptyTransactions (route doesn't exist) - Add actionHref fallback to EmptyCustomers when no onAction prop provided - Improve EmptyTransactions description copy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: clarify Swedish UX copy — terminology, errors, descriptions Terminology consistency: - "Försenad" → "Förfallen" for overdue invoices (customers/[id]) - "bokföringsorder" → actionable description in bookkeeping page - "verifikation har bifogats" → "underlag har bifogats" in doc warning - "Fortsätt ändå" → "Bokför utan underlag" (specific action) Error messages — replace generic "Fel" + "Något gick fel" with specific: - "Något gick fel vid bokföring" → "Transaktionen kunde inte bokföras" - "Något gick fel vid matchning" → "Transaktionen kunde inte matchas" - "Kunde inte hämta X" → "Kunde inte ladda X" + recovery hint - Add "Försök igen" guidance to all error toasts Page descriptions — replace redundant with actionable: - Invoices: "Skapa och hantera" → "Skicka, följ betalningar, skapa kreditnotor" - Bookkeeping: list of features → actionable description Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: design critique — dashboard affordance, reports description Dashboard: - Add ChevronRight indicator to clickable summary cards (Att få betalt, Koppla bank) to distinguish from static cards - Add cursor-pointer to linked cards Reports: - Replace feature list description with actionable guidance "Huvudbok, grundbok..." → "Generera skattedeklarationer..." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace generic "Fel" error toasts with specific messages Deadlines: 5 generic "Fel" → specific per-action titles (create, toggle, edit, delete, load) Expenses detail: 5 generic "Fel" → specific per-action titles (load, approve, pay, credit, delete) Expenses new: 3 generic "Fel" → instructional validation messages (supplier name, supplier selection, invoice number) Customers: 1 generic "Fel" → specific load error with recovery hint All error toasts now follow pattern: title = what failed, description = how to recover Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace all remaining generic "Fel" error toasts (37 instances) Systematic sweep across 12 dashboard pages replacing generic title: 'Fel' with context-specific error titles: - Load errors: "Kunde inte ladda [resurs]" - Action errors: "[Åtgärd] misslyckades" - Validation: "[Fält] saknas" Every error toast now tells the user what failed without needing to read the description. Recovery hints added where missing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: import flow — normalize stat typography, remove console.warn - Replace font-bold with font-display font-medium on 13 stat numbers across SIEPreviewStep, BankFilePreviewStep, BankFileConfirmStep, ImportResultStep (missed by systemic sweep since these are in components/import/, not app/(dashboard)/) - Add tabular-nums to stat numbers displaying counts/currency - Remove console.warn in ArcimMigrationWorkspace Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: final cleanup — console statements, remaining font-bold stats Remove production console statements: - Step1EntityType: remove debug console.warn (dead code after onNext) - TransactionBookingDialog: remove console.error on doc link failure - JournalEntryAttachments: remove 3 console.error calls Normalize remaining font-bold stat displays: - SwipeCategorizationView: 3 instances (completion, amount displays) - NEDeclarationView: yearly result heading + value Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address Greptile review feedback loadMoreTransactions: add inbox item enrichment matching fetchTransactions - Paginated transactions now fetch invoice_inbox_items in parallel - Fixes missing document indicator, template suggestions, and inbox match card for transactions loaded via "Ladda fler" fetchAllPages: add maxPages guard (default 500) to prevent infinite loop - If Arcim gateway returns hasMore:true indefinitely, the loop now exits after 500 pages instead of running forever Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
a1ca96453c |
feat: mobile UX improvements across dashboard (#9)
* feat: mobile UX improvements across dashboard pages - Responsive layouts with stacked mobile forms and grid desktop views - Safe area handling (viewportFit cover, bottom nav insets, main padding) - Touch-friendly dialogs, tabs, and page headers - Mobile nav drawer open/close animation - Dashboard layout parallel Supabase queries - SIE parser: handle quoted VER/TRANS fields - Skip account override for template-based transaction booking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review feedback from Greptile - Fix nav drawer close timer race condition with useRef + clearTimeout - Show locked VAT rate as read-only label on mobile instead of hiding it - Remove dead bottom-16 class overridden by inline style Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
66a4027f1e |
feat: BAS data overhaul, currency revaluation, expenses, UI polish, and cleanup
- Update BAS account catalog with comprehensive SRU codes and K2 flags - Add currency revaluation service with tests and API route - Add expenses page and account deletion API - Enhance booking templates with new patterns and improved tests - Improve transaction categorization with template picker and description matching - Polish dashboard, onboarding, import, and transaction UIs - Refactor year-end service for multi-step closing - Move SRU generator to ne-bilaga, remove standalone SRU export - Remove unused dev docs, mock data, and extension hooks - Add invoice delivery note sequences migration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
4d2140bcf8 |
fix: correct engine column names, dashboard revenue calc, email config, and UX issues
- Fix buildLineInserts() using wrong DB column names (cost_center_id → cost_center, project_id → project) and add missing tax_code field - Replace transaction-based dashboard income/expense with journal-entry-based calculation using account classes (3xxx revenue, 4-7xxx expenses) - Add email/phone fields to CompanySettings type, validate RESEND_FROM_EMAIL in isResendConfigured(), remove unsafe type casts in invoice send/reminders - Always auto-fill line description from account name in JournalEntryForm - Reorder expense lines in TransactionBookingDialog so 1930 is always first row Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
431f385b4b | UX optimization | ||
|
|
44231d0000 |
feat: add transaction booking dialog with manual journal entry
Replace CategoryExpandedDialog with TransactionBookingDialog that embeds the JournalEntryForm for full manual booking. Add /api/transactions/[id]/book endpoint. Add VAT treatment selector to CategoryExpandedDialog. Add booking buttons to TransactionHistoryList and improve TransactionInboxCard actions. Fix animation timing in transactions page state updates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |