a652dcae1ae30209cd75dbdf1de98ec2d265ed88
23
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f829c96d8b |
fix(sie-import): accept tab as field separator (Bollbok exports) (#513)
* fix(sie-import): accept tab as field separator (Bollbok exports) The SIE 4 spec allows either space or tab between fields, but splitSIELine() only treated space (0x20) as a separator. Bollbok exports tab-separated lines for every record except #RAR, which silently swallowed all #IB / #UB / #KONTO / #KTYP / #VER / #TRANS records — imports appeared empty even though the file was well-formed. Also adds a parser-side diagnostic that emits a warning when raw #IB or #VER lines are present in the input but parsing produced none. The previous silent failure is how this bug stayed hidden; the warning gives the import preview something visible to surface next time. Verified against two real reproducer files (Sean / Erik Hellqvist): erik h 2025.SE (UTF-8): 166 accounts, 66 IB, 4 UB, 11 RES, 95 vouchers, 198 TRANS. erik h 2026.SE (CP437): 166 accounts, 66 IB, 4 UB, 0 vouchers. Both now parse with zero warnings/errors. Tests: + 8 Bollbok-shape tab-separated fixtures (2025 + 2026 quoting variants). + 4 silent-failure diagnostic-warning tests. All 74 sie-parser tests pass; 155/155 in lib/import; 64/64 downstream callers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(sie-import): address PR #513 review — strip #KTYP quotes, suppress redundant aggregate warning Two non-blocking P2 findings from Greptile review on PR #513: 1. #KTYP handler stored fields[2] directly, so Bollbok 2026 exports (#KTYP\t1510\t"T") stored '"T"' with literal quotes instead of 'T'. Latent defect — accountType is unused downstream today, but my tab- separator fix made the quoted-value path reachable. Now routes through parseStringField so both Bollbok 2025 (unquoted T) and 2026 (quoted "T") land as 'T'. 2. The aggregate "kontrollera fältavskiljare och teckenkodning" warning fired alongside per-record 'error'-severity issues for malformed #IB / #VER records, producing a misleading hint when the parser had already pinpointed the structural problem. Now suppressed when an error-severity issue with the same tag already exists. Test coverage: + accountType asserted to be 'T' (not '"T"') in both 2025 + 2026 shapes. + VER aggregate-warning test now uses #VER lines without { } blocks (silent loss, no per-record error) — the canonical case the diagnostic is designed for. + New suppression test: bare #VER produces per-record errors AND the aggregate warning is absent. 75/75 sie-parser tests pass; 156/156 in lib/import. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
831920fede |
fix(arcim): allow Fortnox re-sync to replace prior SIE import per fiscal year (#512)
* fix(arcim): allow Fortnox re-sync to replace prior SIE import per fiscal year A user reported a sync failure when retrying Fortnox after adding more verifications: Import failed: Failed to create pending import record: duplicate key value violates unique constraint "sie_imports_company_id_file_hash_active_idx" Root cause: Fortnox embeds the export-time #GEN date in every SIE export, so the file hash always differs between syncs. The wizard's hash-based duplicate detection treated each sync as a brand new file, but the engine still rejected the insert because the per-period import slot was held by the prior 'completed' row. This change reframes Fortnox re-sync as a replace operation rather than a fresh import: - New executeSIEImport option `onExistingPeriod: 'block' | 'replace'`. Manual SIE upload at /api/import/sie keeps default 'block' (current behavior, no regression). The Fortnox /import-sie endpoint passes 'replace', which runs replaceSIEImport on any overlapping completed import before insert. Imported journal entries from the prior import are cancelled per BFL 5 kap 5§; user-created entries (manual, transaction, invoice) are untouched. - /sie-data switches from hash-based to period-based duplicate detection and returns previousImport metadata per fiscal year. - Wizard drops the alreadyImported skip filter, surfaces an amber callout in the confirm dialog listing fiscal years that will be replaced, and shows "ersatte N tidigare importerade verifikationer" per year. - createPendingImportRecord translates 23505 partial-index violations to a clear Swedish recovery message instead of leaking the raw constraint name. - cleanupStaleImportRecords drops the 1-hour age gate and also cleans status='mapped' orphans. SIE imports are single-flight per company so the gate just made legitimate retries fail. - After replace, the fiscal_periods row's opening_balances_set and opening_balance_entry_id are cleared (only when they pointed at the cancelled prior IB entry), so the new IB import isn't skipped. Schema-drift migration captures the partial unique index sie_imports_company_id_file_hash_active_idx that already exists in production (added out-of-band) and drops the now-superseded plain sie_imports_company_id_file_hash_key constraint. Both statements are idempotent — verified no-op against production. Tests: new pg-real test covers the partial index admit-replaced semantics, source_type='import'-only cancellation in replace_sie_import, and the post-replace insert path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(arcim): address PR review — restore 5-min cleanup gate, fix test source_type Greptile P2: `cleanupStaleImportRecords` was deleting `pending` rows unconditionally, which could wipe a concurrent in-flight import in another tab/session. Restored a 5-minute age gate (long enough for any normal interactive import, short enough that legitimate retries after a crash still succeed). Also dropped `mapped` from the cleanup — it is defined in SIEImportStatus but no code path writes it, so including it was both unnecessary and added the concurrent-session risk Greptile flagged. pg-real test: insertPostedEntry used `source_type='transaction'` which is not a valid value per the journal_entries_source_type_check constraint (migration 20260516060000). Switched to `'bank_transaction'` — the actual source_type emitted when a user categorizes a bank transaction in gnubok. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
dec920682f |
Fix/UI changes (#439)
* feat(bookkeeping): add preview for next voucher number in JournalEntryForm * feat(encoding): implement U+FFFD recovery for Swedish text in encoding functions |
||
|
|
a53a119a2e |
Fix/vat parent accounts (#438)
* feat(enable-banking): add support for account selection and syncing - Updated StoredAccount interface to include an 'enabled' flag for account syncing preferences. - Enhanced ensureFiscalPeriod function to handle overlapping fiscal periods with posted entries and opening balances. - Added tests for fiscal period validation and account syncing logic. - Implemented AccountPickerDialog component for user account selection. - Created API routes for PATCH /accounts and POST /sync to manage account syncing. - Introduced 'pending_selection' status for bank connections to allow user account selection before syncing. - Updated database migration to support new connection status and backfill existing accounts with enabled=true. * feat(enable-banking): implement account selection and consent event logging --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
11e07b34c3 |
fix(sie-import): reject overlap-but-not-contain fiscal periods (#421)
* fix(sie-import): reject overlap-but-not-contain fiscal periods ensureFiscalPeriod previously fell back silently to any partially-overlapping fiscal_period when no period fully contained the SIE file's #RAR range. That stamped every imported voucher with a fiscal_period_id whose date window didn't cover the voucher's own entry_date — breaking the SIE invariant that #VER dates fall inside #RAR and BFL 5 kap. (verifikationsnummer i obruten serie per räkenskapsår). Reproduced in production: a customer with a broken fiscal year (Mar–Feb) had their previous-year SIE collapse into a calendar 2026 period, mixing 116 prior-year vouchers into the current period's voucher sequence. Now: fully-contained → reuse; partial overlap → reject with a clear Swedish message pointing at the period dates that would need to be fixed; no overlap → create a new period as before. Adds a defense-in-depth pre-check in executeImport that rejects with a Swedish error if any individual #VER date falls outside the resolved fiscal period — catches multi-year SIE files (which gnubok does not yet support) without producing corrupted journal entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(sie-import): fail closed on period-fetch error in voucher-date guard Greptile correctly flagged that the voucher-date guard wrapped the period fetch in `if (resolvedPeriod)` without checking the .single() error. A transient network error or RLS failure returned null for data, the guard body skipped, and importVouchers ran with no date validation — the same data-corruption path the guard exists to close. Now: surface the fetch error to the user (Swedish) and abort the import. Also switches the date comparison from millisecond timestamps to YYYY-MM-DD string compare. SIE per spec is date-only and our parser normalizes to midnight, but string compare matches the underlying DATE columns exactly and removes a latent off-by-one risk on the period's last day if a future parser change ever attached a time component to v.date. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4131db2894 |
chore: MCP intent-tools, BankID enrichment table, multi-tenant fixes (#402)
* chore: MCP intent-tools, BankID enrichment table, multi-tenant fixes MCP server gains six intent-shaped tools that collapse multi-call agent flows into one: vat_close_check, query_journal, auto_match_period, create_supplier_invoice_from_inbox, audit_package, year_end_readiness. Tools wired into TOOL_SCOPE_MAP and OPERATION_RISK_TIERS as appropriate (create_supplier_invoice_from_inbox at medium tier — reversible until approve, but stages a leverantörsskuld). BankID enrichment now persists to a dedicated bankid_enrichment table keyed by user_id. extension_data has been company-scoped (NOT NULL company_id) since the multi-tenant refactor, so every BankID signup has silently been failing the enrichment upsert. Select-company picker reads from the new table. delete_last_voucher (BFNAR 2013:2) needs to clear document_attachments.journal_entry_id before deleting the entry, but the new document immutability trigger blocks that UPDATE. Added the same gnubok.allow_delete transaction-scoped bypass pattern used by the journal-entry/line/retention triggers. pg-real tests cover the happy path, the unauthorized direct UPDATE, and the swap-to-different-entry attempt under the bypass flag. fiscal_periods.no_overlapping_fiscal_periods exclusion was scoped to user_id from before multi-tenant — rebound to company_id so the same user can have overlapping fiscal years across companies they own/are member of. Also adds scripts/seed-demo-account.ts for end-to-end demo seeding (two companies, full FY2025, active FY2026 with mixed state). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(pr-402): address review feedback Migrations - Drop 20260506140000_document_journal_entry_immutability_delete_bypass.sql: redundant with 20260506140000_document_journal_entry_immutability_bypass.sql that landed on main while this branch was open. Both share the same gnubok.allow_delete pattern; main's version is what the DB actually has. - Rename 20260506150000_bankid_enrichment_table.sql → 20260506160000_bankid_enrichment_table.sql to clear the timestamp clash with 20260506150000_protect_document_journal_link.sql on main (Supabase branch preview was failing on schema_migrations PK collision). Tests - Drop the swap-under-flag test from delete-last-voucher.pg.test.ts: main's bypass returns NEW unconditionally when gnubok.allow_delete='true', so the swap is permitted. Drop the duplicate happy-path test (already covered by 'clears journal_entry_id on attached documents and deletes the voucher'). Keep the unauthorized-direct-UPDATE test. - Add bankid-enrichment.pg.test.ts covering the SELECT RLS policy: user reads own row, cannot read another user's row, INSERT denied for authenticated. gnubok_query_journal - amount_min/amount_max is applied post-fetch (PostgREST can't OR abs(debit) and abs(credit) cleanly), but PostgREST's count is computed pre-filter. Reporting that as total_lines mislead agents into paginating a tail that was already filtered out. When the amount filter is applied, anchor total_lines and truncated to the filtered set and surface db_matched_pre_amount_filter + amount_filter_applied_post_fetch separately. - Escape `_` in the free-text LIKE filter so a search for "2_441" doesn't match "2X441". VAT close check - Reverse-charge blocker no longer fires on ruta 30 (seller-side domestic omvänd skattskyldighet) — the seller books no VAT, the buyer does, so missing ruta 48 is expected. Now scoped to ruta 31/32 (EU acquisition) where the buyer must book both calculated output (2615) and matching ingående moms (2645). - High-value receipt threshold no longer reads journal_entries.total_amount (column doesn't exist; check silently never fired). Sums debits across the entry's lines, which equals the gross for ordinary purchase entries — comparing a gross figure against the BFL/ML 4 000 SEK threshold per ML 17 kap 26–28 §. seed-demo-account.ts - Require an explicit email argument; refuse to run with the previously hardcoded fallback that would silently target a real user. Ensure email is non-undefined for downstream typing. - Type the supabase fiscal_periods insert result locally so tsc no longer reports 'fp implicitly any' from the loose untyped client. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): adjust fiscal-period-start-day pg test for per-company overlap The pg-real failure on PR #402 was a latent bug surfaced by this branch's fiscal_periods exclusion constraint flip from user_id to company_id (migration 20260506140100). The test was inserting periods that overlapped seedCompany's default 2026-01-01..2026-12-31 period; the previous constraint slipped past it because the test's INSERT didn't set user_id (NULL escapes the WITH = match), so two same-company overlapping periods silently coexisted. Now that the constraint correctly fires per company, pick years that don't overlap with the seeded 2026 period. The trigger's behavior under test (allow mid-month start when no earlier period exists, allow back-dated SIE imports, reject mid-month start when an earlier period exists) is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(vat-close-check): correct reverse-charge/import blocker rutor Rutor 30/31/32 are the buyer's calculated utgående moms on reverse- charge purchases (domestic byggtjänster/electronics → 2614 → ruta 30; EU goods → 2624 → ruta 31; EU services → 2634 → ruta 32). The buyer must also book matching ingående moms (2647 inhemskt / 2645 utlandet → ruta 48). The previous fix removed ruta 30 on the basis that it was seller-side; that's incorrect — domestic-RC sellers book no VAT at all (they report only beskattningsunderlag on ruta 41), so 2614 only sees buyer-side entries. Restore ruta 30. Also extend the check to import rutor 60/61/62 (non-EU import VAT declared via momsdeklaration since 2015 — 2615/2625/2635). Same mechanic: importer books output VAT on these rutor and deducts the input side via ruta 48. SaaS-from-AWS / OpenAI / Vercel companies hit this path; without including 60/61/62 the blocker would silently miss their misbookings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(mcp): expose ruta 60/61/62 (import VAT) on the local VatReportResult The vat-close-check fix referenced vatReport.rutor.ruta60/61/62 but the MCP server's local VatReportResult type only carries ruta 05-49. Build broke on tsc. Extend the MCP server's slim VAT report to also project import VAT — 2615 → ruta 60 (25%), 2625 → ruta 61 (12%), 2635 → ruta 62 (6%) — and fold those into ruta 49 (att betala/återfå). Mirrors the BAS-to-Ruta mapping in lib/reports/vat-declaration.ts. Output schema and required list updated accordingly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1a6b407a60 |
Supp/verifikationer inconsitency (#369)
* feat(bookkeeping): implement reset bookkeeping functionality with safeguards * feat(migrations): restore relaxed trigger for retroactive first fiscal year |
||
|
|
24107338fa |
Fix/balance inconsitency (#306)
* feat: implement fiscal period date fields component and validation logic * feat: update fiscal period validation and naming logic * feat: implement RPC for computing prior opening balances - Added `compute_prior_opening_balances` RPC to aggregate opening balances for balance-sheet accounts when no opening balance entry is set. - Updated tests across various reports to utilize the new RPC for fetching prior balances. - Refactored `getOpeningBalances` to call the RPC when necessary, improving performance and reliability. - Introduced a script to repair fiscal period chains for companies with broken periods, ensuring proper linking and continuity. - Enhanced error handling and validation in the repair script to ensure data integrity during the process. * feat: implement duplicate opening-balance repair for multi-year SIE imports * feat: enhance SIE entry listing and deduplication logic for opening balances * fix: refine companyHasPriorActivity logic to exclude storno entries and improve balance counting |
||
|
|
885dd8a2e4 |
feat: implement fiscal period date fields component and validation logic (#301)
* feat: implement fiscal period date fields component and validation logic * feat: update fiscal period validation and naming logic |
||
|
|
b5df2fb292 |
feat: invoice-inbox polish + SIE source voucher traceability (#299)
* fix: consolidate commit_journal_entry to single 4-arg signature Replaces the phantom-overload drop migration with an idempotent consolidation that leaves only the 4-arg-with-defaults signature, callable with either 2 or 4 named args. Fixes the "Could not choose the best candidate function" ambiguity caused when the commit-metadata migration CREATE OR REPLACE'd a 4-arg version alongside the existing 2-arg one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: preserve SIE source voucher identity on journal entries Adds source_voucher_series / source_voucher_number columns to journal_entries so per-verifikat traceability survives the importer's skip-empty-voucher logic. The SIE importer populates the original series/number even when skipped vouchers cause gnubok's target numbering to drift from the source file's sequence. Required for BFNAR 2013:2 kap 8 behandlingshistorik. - Migration adds columns + partial index + extends immutability trigger - importVouchers() records rawSeries/rawNumber per voucher - JournalEntry type + test fixtures gain the new fields - Bookkeeping detail page surfaces "Ursprungligt verifikat" when present Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: polish invoice-inbox workspace for production use - Bedrock image fit: shrink images > 5 MB via sharp before Bedrock upload so HEIC/high-res phone photos don't fail with the 5 MB cap - Swedish error mapping: toSwedishInboxError translates Bedrock / infrastructure errors to Swedish sentences stored in error_message - History timeline endpoint (GET /items/:id/history) returns the processing_history events correlated to the inbox item - Workspace UI: inline diagnostic timeline inside the convert dialog, same-email row grouping ("+N dokument" chip), inferred-VAT affordance with "needs review" signalling, Riksbanken exchange-rate prefill for foreign-currency invoices so the supplier-invoice create path populates *_sek audit columns Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: extend inbox-smart-match to supplier invoices Both receipts and supplier invoices expose structurally identical match anchors (date, amount, currency, counterparty name) so the matcher can reuse the same narrowing + LLM prompt. Adds getMatchAnchors() as a shared extractor across ReceiptExtractionResult / InvoiceExtractionResult, and updates the event handlers to process supplier_invoice items alongside receipts. LLM prompt re-phrased as "dokument" rather than "kvitto" and loosened the date-window heuristic since invoice payments can lag behind the invoice date by weeks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: drop unused category selector from TransactionForm The manual "Lägg till transaktion" dialog predates the current categorization flow (SwipeCategorizationView, BatchCategorySelector, AI suggestions). The category dropdown here never drove journal-entry creation — onSubmit fanned it out to CreateTransactionInput.category, which is optional. Removes the dropdown, the unused watch() hook, and the categories lookup table. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(migrations): restore drop-phantom file and rebump timestamps Supabase branch DB failed with PK violation on schema_migrations because my two migrations collided with timestamps already on main: 20260421120000 → journal_entries_with_related_rpc (PR #298) 20260421130000 → drop_legacy_supplier_invoice_user_id_uniqueness (PR #296) Rebumped to 20260421140000 and 20260421150000 so each migration has a unique version (Supabase uses only the 14-digit prefix as the PK). Also restored the 20260420130000_drop_phantom_commit_journal_entry_overload migration I had deleted — CLAUDE.md rule #5 forbids modifying existing migrations. My consolidate migration is still compatible: drop_phantom drops the 4-arg overload (no-op where absent), then consolidate recreates it with defaults. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(inbox-smart-match): anchor invoices on dueDate with wider window The original ±7d window around invoiceDate filtered out all real payments for invoices with standard 30–60 day terms — the matcher would see zero candidates before the LLM was called, making the supplier-invoice matcher effectively dead. New anchor selection: - Receipts: receipt date ±7 days (unchanged; paid on the spot) - Invoices with dueDate: dueDate ±14 days (covers early/late payments) - Invoices without dueDate: invoiceDate -7/+45 days (covers 30-day terms) MatchAnchors now carries windowDaysBefore/After so the window can vary per document shape. Added three getMatchAnchors tests asserting window sizes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
23664e79cb |
feat: multi-series SIE import, reusable FiscalYearSelector, library templates in picker (#278)
* feat: multi-series SIE import, reusable FiscalYearSelector, library templates in picker - SIE import preserves each voucher's source series (B/C/I/V/...), essential for Fortnox migrations where series carry semantic meaning (kundfakturor, inbetalningar, etc.). Target numbering still goes through next_voucher_number per series; source (series, number) is stored in the migration mapping for BFNAR 2013:2 audit trail. - Execute route reads company_settings.default_voucher_series as the fallback for vouchers arriving without a series (SIE4I). - Extract shared FiscalYearSelector component; adopt in /reports and /bookkeeping. - Transaction TemplatePicker now surfaces user-created library templates (company + team scope) alongside the static registry, with a helper to convert simple library templates into the BookingTemplate shape. - Exclude 8999 "Årets resultat" from income statement financial section and monthly breakdown so year-end closing entries don't cancel the net result. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: skip Bokio SIE regression when fixtures are absent /dev_docs is gitignored (contains anonymised customer exports), so the integration test can't find its input files in CI. Gate the suite on fixture presence so it still runs locally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: address Greptile review feedback - convertLibraryToBookingTemplate: default entity_applicability to 'all' when the source template has no entity_type, so TemplatePicker doesn't silently hide it for companies with a set entity type. - FiscalYearSelector: fire onReady in the no-company early-return branch so consumers (e.g. ReportsPage) don't get stuck in a loading skeleton while the company context is still hydrating. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
8ed943198f |
fix: allow retroactive first fiscal year via SIE import (#265)
The enforce_period_start_day trigger and its sie-import pre-validation rejected any non-first-of-month period_start whenever *any other* fiscal period existed for the company. That blocked a real user flow: after onboarding creates a default period (e.g. current year, day 1), importing an SIE for an older förlängt första räkenskapsår (e.g. 2017-07-28 – 2018-12-31) failed with "Non-first fiscal period must start on the 1st of a month". Per BFL 3 kap., the chronologically first fiscal year is the one that may be 6–18 months and start mid-month — which is a property of *when* the period starts relative to others, not of insert order. The trigger and pre-validation now allow mid-month start iff no existing period starts earlier. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c8a5f044c3 | feat: add ensureFiscalPeriod function and related tests for fiscal period validation (#264) | ||
|
|
6ccd4f429c |
fix: Swedish VAT compliance — representation, domestic RC, full 26xx mapping, SIE (#206)
* feat: add INK2 declaration improvements, invoice delivery date, and Swedish compliance skills Expand INK2 engine with full INK2S/INK2R support and improved SRU generation. Add delivery_date field to invoices and corresponding PDF/migration support. Add Claude skills for Swedish asset accounting, invoice compliance, SIE import/export, SRU filing, and tax planning. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review — map BAS 4500–4899, strip CRLF in SRU, document P3 - Map BAS accounts 4500–4599 (legoarbeten), 4700–4899 (diverse varuinköpskostnader) to SRU 7512 so they are not silently dropped from INK2R declarations - Strip \r\n in sanitizeString to prevent CRLF injection in SRU fields - Document P3 period suffix limitation for brutet räkenskapsår Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: correct BAS 4500-4599, 4700-4899 mapping from 7512 to 7511 Per the official BAS-to-SRU mapping, these account ranges are cost of goods (legoarbeten, inkurans, svinn) and belong under 7511 (Råvaror och förnödenheter), not 7512 (Handelsvaror). 7512 remains 4600-4699. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: Swedish VAT compliance — representation VAT, domestic RC, full BAS 26xx mapping, SIE encoding - Representation expenses now default to reduced_12 VAT (ML 13 kap 24-25 §§); income tax deduction was abolished 2017 but VAT deduction at 12% remains - Domestic reverse charge (byggtjänster etc.) uses 2647 instead of 2645, with distinct line descriptions for Swedish vs EU/non-EU RC - VAT declaration maps all BAS 26xx variant accounts (egna uttag 2612/2622/2632, uthyrning 2613/2623/2633, VMB 2616/2626/2636, import 2615/2625/2635, domestic RC 2647, frivillig skattskyldighet 2642) and revenue variants (3108/3105/3004/3100) to correct momsdeklaration rutor - SIE parser: remove unreliable #FORMAT PC8 encoding detection (most software exports UTF-8 with PC8 header), parse #FLAGGA for import-already-done warning, default SIE type to 1 when absent, fix RTRANS/BTRANS documentation - SIE export: add #RAR -1 (previous fiscal year), fix UB = IB + movements - Error messages: add pattern matching for locked period trigger errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address Greptile review — update ruta49 JSDoc, use null sentinel in error map Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
211033410c |
Fix/import data (#200)
* fix: enhance import data handling and consent management across components * feat: Enhance SIE import functionality with validation and error handling improvements - Added validation errors and warnings state management in SIEImportWizard. - Improved error handling for duplicate, validation, and parsing errors during SIE file import. - Enhanced user feedback with actionable guidance for common import errors. - Updated SIEUploadStep to display validation errors and warnings. - Improved error messages in API routes for better clarity and user experience. - Added file size and type validation in the SIE parse route. - Enhanced parsing logic to provide more detailed error messages for unbalanced vouchers and missing amounts. - Created a new storage bucket for SIE file archival in Supabase with appropriate policies for user access. - Updated tests to reflect changes in error messages and validation logic. * fix: Improve type assertion for response in getPage method * Update extensions/general/arcim-migration/lib/migration-orchestrator.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update supabase/migrations/20260408130000_sie_files_storage_bucket.sql Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: Add company ID verification for consent handling in accept and disconnect endpoints --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> |
||
|
|
d0b3f21bde |
feat: remove AI extensions, restructure settings, and add atomic voucher commits (#157)
Remove AI-dependent extensions (ai-chat, ai-categorization, receipt-ocr, invoice-inbox) and their infrastructure (lib/ai/*, ai-consent, LangChain/ Anthropic/OpenAI deps) to simplify core and reduce bundle size. Restructure monolithic settings page into dedicated sub-pages (company, bookkeeping, invoicing, tax, banking, api, account, team, templates) with shared layout and sidebar navigation. Add atomic commit_journal_entry RPC so voucher number increment and status update happen in a single transaction — prevents burned numbers on constraint failures. Add continuity check report and voucher gap explanation tracking. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
0dd1f5ebc1 |
feat: multi-tenant company refactor (GNU-19) (#153)
* feat: multi-tenant company refactor (GNU-19) Introduce companies table, company_members, and user_preferences to support multiple companies per user. All data scoping changes from user_id to company_id across the entire codebase. Key changes: - Database migration: new tables, company_id on 40+ tables, backfill, RLS rewrite from user_id to company-member-based, updated RPCs - Types: Company, CompanyMember, CompanyRole, UserPreferences types; company_id added to all entity interfaces; companyId on all events - Engine: all 7 core functions take companyId; storno, period, year-end services updated; 16 report generators updated - Middleware: company context resolution (cookie → prefs → first company) - API routes: ~120 routes updated with requireCompanyId() - Frontend: CompanyProvider context, layout/dashboard/onboarding updated - Extensions: context factory, 9 extensions, all lib files updated - Tests: 1880 tests passing, all helpers updated with company_id defaults Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add database migrations for multi-tenant company and team system (GNU-19) Adds company_invitations, company creation RPC, team_members, account deletion RPC, and teams table refactor migrations. Updates base multi-tenant migration with cascading FKs and onboarding_step column. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add team types and update core infrastructure for multi-tenancy (GNU-19) Adds TeamRole, MemberSource, and Team types. Refactors Supabase service client to be stateless, updates middleware for team-aware routing, extends CompanyContext with team/role fields, and updates extension service types to accept companyId. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: thread company_id through business logic functions (GNU-19) Replaces user_id scoping with company_id across all lib modules: bookkeeping, documents, transactions, invoices, reconciliation, tax, deadlines, and import. Updates corresponding tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: thread company_id through API routes and extensions (GNU-19) Updates all existing API routes to extract and pass companyId. Updates enable-banking and arcim-migration extensions for company-scoped transaction ingestion and sync. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add company and team management API routes (GNU-19) Adds CRUD endpoints for company members, company invitations, team members, and team invitations. Includes invite token utilities, email templates, and company switch server action. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add team/company UI components, pages, and dashboard updates (GNU-19) Adds CompanySwitcher, ConsultantEmptyState, Step0RoleChoice, company members and team management panels. Updates dashboard layout for team-aware routing, onboarding for multi-step role choice, and auth callback for team invite acceptance. Ignores supabase/.branches/. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add null guards for company in import page (GNU-19) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: move appUrl declaration to outer scope in invite route (GNU-19) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add optional chaining for company.name in members section (GNU-19) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add optional chaining for second company.name in members section (GNU-19) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add null guards for company in extension components (GNU-19) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: pass companyId to executeSIEImport in arcim-migration extension (GNU-19) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update tests to use companyId instead of userId and improve type handling --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
2ad8731dc9 |
feat: arcim migration wizard UX, import fixes, Sentry setup (#22)
* 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> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
e8fb84b4fd |
feat: import system improvements, INK2 fix, and Swedish text corrections (#10)
- 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> |
||
|
|
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> |
||
|
|
15fcb7e067 |
fix: correct account-mapper test to match bas_range fallback behavior
The test expected empty BAS reference to leave 1510 unmapped, but the bas_range fallback correctly self-maps valid 4-digit BAS accounts with confidence 0.9. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
39e407644d |
feat: unified document inbox, full BAS 2026, and document-transaction matching
- Expand BAS reference from ~180 to ~1,276 accounts (full BAS Kontoplan 2026) with K2 exclusion flags, per-class data files, and computed SRU codes - Evolve invoice inbox into unified document inbox handling invoices, receipts, and government letters with AI-powered classification (Claude Haiku Vision) - Add multi-pass document-to-transaction matching engine with greedy assignment for both supplier invoices (reference/amount/date/name) and receipts (weighted amount/merchant/date scoring) - Add supplier invoice matching in transaction ingest pipeline - Inject booking template suggestions into AI extraction prompts - Surface matched documents in swipe categorization UI with one-tap booking - Auto-activate missing BAS accounts during SIE import against full reference - Add K2 filter toggle in Chart of Accounts manager - Add receipt confirmation route with BFNAR representation fields - Add database migrations for K2 support and document matching columns - Remove obsolete extension migration scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
91e2c1705a |
feat: per-line VAT, invoice document types, ledger-based VAT declaration, bank reconciliation, and pagination
Per-line VAT rates: - Add generatePerRateLines() to group invoice items by vat_rate with separate revenue + VAT lines per rate group (invoice-entries.ts) - Add getAvailableVatRates() and getVatTreatmentForRate() (vat-rules.ts) - PDF template shows per-line VAT column and per-rate totals for mixed-rate invoices - Invoice create/review UI supports per-line rate selection - Types: add vat_rate/vat_amount to InvoiceItem, vat_rate to CreateInvoiceItemInput Invoice document types (proforma, delivery note): - Add InvoiceDocumentType, document_type and converted_from_id to Invoice type - PDF hides prices for delivery notes, adds proforma notice - Email templates support all document types - mark-paid skips journal entries for non-invoice document types - Migration 031: invoice_document_type Accounting method support: - Add AccountingMethod type (accrual/cash) - Migration 032: add_accounting_method column to company_settings VAT declaration rewrite: - Rewrite to read directly from general ledger (26xx/3xxx account lines) instead of aggregating invoices/transactions/receipts - ACCOUNT_RUTA mapping drives momsdeklaration boxes from GL balances Bank reconciliation: - Transaction ingest now pre-fetches unlinked GL lines and attempts auto-reconciliation during import - Add transaction.reconciled event type - Add ReconciliationMethod type and reconciliation_method on Transaction - Migration 030: bank_reconciliation - New reconciliation engine, API routes, and BankReconciliationView component Pagination (fetchAllRows): - New lib/supabase/fetch-all.ts overcomes PostgREST 1000-row limit - Adopted in all report generators, SIE/SRU export, account list APIs Fiscal period validation: - New validate-period-duration.ts enforces max 18 months per BFL 3 kap. - Applied in period-service.ts and fiscal-periods API Account mapper simplification: - Remove Levenshtein/fuzzy matching, use exact account number match only Swedbank parser improvements: - Support abbreviated headers (Clnr, Bokfdag, Radnr) - Use Referens column as counterparty Chart of accounts management: - Add DELETE endpoint with system account and usage protection - PUT uses partial updates - New AccountCombobox, AddAccountDialog, EditAccountDialog, ChartOfAccountsManager Tax deadline corrections: - Rewrite inkomstdeklaration_ab using Skatteverket lookup table - Rewrite arsredovisning deadline to 7 months after FY end per ÅRL 8:3 Onboarding first fiscal year: - Add first fiscal year toggle with date pickers and 18-month validation UI terminology: - Change "okategoriserad/kategorisera" to "obokförd/bokföra" throughout Report column fix: - Fix start_date/end_date to period_start/period_end in report queries Supplier invoice input: - CreateSupplierInvoiceItemInput uses amount field (legacy quantity/unit_price kept) Misc: - SIE import uses upsert for idempotent account creation - account-descriptions.ts falls back to BAS reference data - Add invoice_default_notes to CompanySettings - Update CLAUDE.md to reflect current project state Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |