* fix(underlag): a verifikat a customer invoice points at is backed by it; PS follows the invoice link (#2298)
The invoice-to-verifikat link is written on the invoice side only
(invoices.journal_entry_id, invoice_payments.journal_entry_id), while the
missing-underlag predicate and the periodisk sammanstallning resolved the
invoice from the entry's own source columns. A SIE-imported sale matched to
its invoice afterwards therefore kept warning "Underlag saknas" and was left
out of the EU sales list, although the account-based momsdeklaration showed
it and the verifikat page already listed the invoice as its underlag.
- verifikat_without_documents / transactions_without_documents: customer-
invoice hanvisning arm (BFL 5 kap 7 §), tenant-scoped on the link row;
new migration 20260906135702, pinned by a pg-real test.
- getInvoiceReferencesForJournalEntries(): one TS mirror of that arm, used
by the journal-list filter and bulk exempt, /api/documents/counts (new
invoice_references map) and the transactions list; the push cron mirrors
it with its global reads.
- Journal list: no "Underlag saknas" chip for a covered entry, matching
the engine's own invoice rows and the verifikat detail page.
- Periodisk sammanstallning: entries fetched by their EU-revenue lines and
attributed through every link (engine source_id, invoices.journal_entry_id,
invoice_payments.journal_entry_id); kontantmetod invoice_cash_payment
entries are filed too, which the old source_type filter dropped.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019SaJfqNi4VmsG8FMKq99G6
* fix(underlag): issued invoices only, blocking mixed-customer settlements in PS, chunk-level degrade (#2298 review)
- The customer-invoice hanvisning arms (RPCs, both TS resolvers, push cron)
now require an ISSUED invoice: status not in ('draft', 'cancelled'), the
schema's own definition (migration 20260427150000). NON_ISSUED_INVOICE_
STATUSES in lib/invoices/matchable-statuses.ts is the shared constant; the
pg test pins a draft-linked and a cancelled-payment entry as still missing.
- Periodisk sammanstallning: one verifikat linked to invoices of different
customers is no longer attributed to the first invoice; it is left out of
the accumulators and reported once as a blocking MIXED_CUSTOMER_SETTLEMENT
naming the voucher, the customer count and the amount. Same-customer
settlements are filed in full.
- Transactions list: a failed invoice-reference lookup leaves that chunk's
verdict unknown (no badges) and continues with the remaining chunks instead
of abandoning them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A verifikat booked from a supplier invoice showed the invoice PDF when opened
while the list kept warning "Underlag saknas" on the same row. Both surfaces
behaved as written: every missing-underlag surface only accepts a referenced
supplier-invoice document when it is ANCHORED to a journal entry (only anchored
docs sit behind block_document_deletion), while the verifikat view's reference
resolver displayed the document regardless.
The document was floating because delete_last_voucher clears journal_entry_id
on everything attached to the voucher it tears down (the FK is ON DELETE
RESTRICT, so it must). Deleting a rättelse the invoice PDF had been relinked
onto therefore orphaned it while the payment verifikat stayed posted, and
nothing ever anchored it again: the warning was unresolvable by design.
Same class one surface over: v1 mark-paid never linked the document at all,
dashboard mark-paid only did so for the cash entry, and both
match-supplier-invoice routes propagated the transaction's document but not the
invoice's own. Four of the five affected prod rows come from those paths, not
from a deleted voucher.
- lib/core/documents/supplier-invoice-underlag.ts: anchor a floating document
to the invoice's own posted verifikat (registration, then payment, then
partial payments; open unlocked periods only). Never moves an anchored doc,
never throws.
- Called after delete_last_voucher and from all four payment paths.
- getJournalEntryUnderlagReferences withholds an unanchored document so the
verifikat view and the warning can no longer contradict each other.
- Migration 20260727180000 backfills the rows already in this state.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: prevent credit notes from entering payment flow
* fix: persist and display customer personal numbers
* feat: configure automatic invoice reminder days
* fix: issue credit notes through send flow
* chore: add repository agent guidance
* feat(mcp): route tools across user companies
* fix(articles): delete unused register entries
* feat(invoices): improve issued invoice actions
* feat(supplier-invoices): retain uploaded source documents
* docs: record implementation decisions
* feat: enhance customer personal number handling and validation
- Updated CustomerForm to allow personal numbers in the format of "********-1234" for individual customers.
- Added validation to ensure personal numbers are only accepted for individual customers in CreateCustomerSchema.
- Implemented masking and encryption for personal numbers to enhance data protection.
- Introduced new utility functions for masking and encrypting personal numbers.
- Added database migration to enforce unique constraints on credit note relationships and prevent duplicate entries.
- Enhanced error handling and logging for credit note issuance and invoice processing.
- Updated tests to cover new credit note creation guards and personal number handling.
* test: enhance list companies test with supabase query mocks
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>
* fix(import): SIE bulk-delete on service client + provider/reporting/banking fixes
Rebuilt branch onto main as a single commit.
- import: run SIE bulk-delete RPCs on the service client to escape the 8s
statement_timeout; undo_sie_import now takes an explicit actor (p_user_id)
so its owner/admin gate works when auth.uid() is NULL on the service
client (migration 20260624120000) + pg-real regression test
- providers: distinguish missing Fortnox license from expired connection;
provider_consent_tokens PK regression test
- reports: include unmapped BAS expense groups in the income statement
- enable-banking: reconnect closed/expired bank sessions in place
- bookkeeping: surface linked invoices as underlag on the verifikat view
- scripts: track BL cleanup/diagnostic tooling; data files (*.csv) are
git-ignored and consentId is now a required arg with no silent default
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(import): add Cache-Control header to journal entry references response
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>