b5df2fb292
* 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>
61 lines
2.8 KiB
PL/PgSQL
61 lines
2.8 KiB
PL/PgSQL
-- Persist the original voucher identity (series + number) from an SIE source file
|
|
-- on each journal entry, for per-verifikat traceability from source system → gnubok.
|
|
--
|
|
-- Context: when the SIE importer skips an empty/single-line/unbalanced voucher,
|
|
-- subsequent vouchers end up with gnubok numbers that drift from the source
|
|
-- numbers. Today the source→target mapping lives only on
|
|
-- sie_imports.migration_documentation (JSONB array), so an individual
|
|
-- verifikat has no way to expose its original SIE id for search or display.
|
|
--
|
|
-- BFNAR 2013:2 kap 8 behandlingshistorik: a migration must preserve auditable
|
|
-- traceability. These columns denormalize the mapping onto each entry for
|
|
-- per-verifikat lookup without altering the aggregate JSONB audit record.
|
|
--
|
|
-- Scope: populated only by SIE import bulk insert (source_type='import'). Left
|
|
-- NULL for opening-balance and reconciliation entries (no single source VER),
|
|
-- and for all non-SIE sources (manual, invoice, bank, etc.).
|
|
|
|
ALTER TABLE public.journal_entries
|
|
ADD COLUMN source_voucher_series TEXT,
|
|
ADD COLUMN source_voucher_number INTEGER;
|
|
|
|
-- Index supports "find imported entry by original SIE number" lookups.
|
|
CREATE INDEX idx_journal_entries_source_voucher
|
|
ON public.journal_entries (company_id, source_voucher_series, source_voucher_number)
|
|
WHERE source_voucher_series IS NOT NULL;
|
|
|
|
-- Extend the immutability trigger to cover the new columns — matches the
|
|
-- pattern applied to commit_method/rubric_version in 20260420120000.
|
|
CREATE OR REPLACE FUNCTION public.enforce_journal_entry_immutability()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF TG_OP = 'DELETE' THEN
|
|
RAISE EXCEPTION 'Cannot delete journal entries (id: %, status: %). Use cancelled status instead.',
|
|
OLD.id, OLD.status;
|
|
END IF;
|
|
|
|
IF OLD.status = 'draft' AND NEW.status IN ('draft', 'posted', 'cancelled') THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
IF OLD.status = 'posted' AND NEW.status IN ('reversed', 'cancelled') THEN
|
|
IF NEW.status = 'reversed' THEN
|
|
IF NEW.description != OLD.description OR NEW.entry_date != OLD.entry_date
|
|
OR NEW.fiscal_period_id != OLD.fiscal_period_id
|
|
OR NEW.voucher_number != OLD.voucher_number
|
|
OR NEW.commit_method IS DISTINCT FROM OLD.commit_method
|
|
OR NEW.rubric_version IS DISTINCT FROM OLD.rubric_version
|
|
OR NEW.source_voucher_series IS DISTINCT FROM OLD.source_voucher_series
|
|
OR NEW.source_voucher_number IS DISTINCT FROM OLD.source_voucher_number THEN
|
|
RAISE EXCEPTION 'Cannot modify fields of a posted entry during reversal (id: %)', OLD.id;
|
|
END IF;
|
|
END IF;
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
RAISE EXCEPTION 'Cannot modify a % journal entry (id: %). Committed entries are immutable per Bokforingslagen.',
|
|
OLD.status, OLD.id;
|
|
END; $$;
|
|
|
|
NOTIFY pgrst, 'reload schema';
|