* feat(invoices): bulk Bokfor, per-view filter counts, review-queue draft CTA
Customer feedback: MCP-created invoices land in Granskning and then sit as
unnumbered drafts that each need individual issuance, and the list filter
gives no signal about where the work is.
- New POST /api/invoices/bulk-book: drafts get an F-number + mark-sent
semantics (no email) and book inline when the company books at issue;
sent/overdue unbooked invoices get the deferred /book semantics.
Sequential loop keeps voucher numbers ordered; per-item Swedish errors.
- Extracted the shared cores into lib/invoices/issue-and-book-invoice.ts
and lib/invoices/book-invoice-deferred.ts, now used by the per-id
mark-sent and book routes AND the bulk loop, so they cannot drift.
Per-id route behavior unchanged (existing route tests untouched, green).
- Invoice list: multi-select with hover-reveal checkboxes (supplier-invoices
shape), bulkbar with mode-aware action label, ConfirmationDialog with a
draft/sent breakdown, one aggregate toast. Kontantmetoden hides selection
entirely.
- ContextPicker: count annotations on every status view via the one shared
predicate (counts always match rows), active view written back to the URL
(?status=) for shareable views. No seg/chip row: founder-locked pattern.
- Granskning: after a bulk approve that committed create_invoice ops, the
summary toast links to /invoices?status=draft to finish with bulk Bokfor.
Verified: npm run lint clean, npm test 13845 passed, npm run check:guards
passed. New tests: bulk-book route (11), issueAndBookInvoice (7),
bookInvoiceDeferred (7).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(invoices): bulk-book review findings, deferred drafts, dupes, URL params
- Deferred-booking companies (accrual + defer_invoice_booking): a draft in
bulk-book no longer gets silently ISSUED (F-number consumed, marked sent,
invoice.sent emitted) while reporting status 'booked' with a null
journal_entry_id. The draft branch now requires booksInvoicesOnIssue();
otherwise the item fails per-row with the new INVOICE_BOOK_DEFERRED_DRAFT
code (Swedish + English) before the invoice is touched.
- Duplicate ids in one request no longer double-book: the second iteration
read the stale pre-loop snapshot, passed the already-booked check, and
minted a voucher the CAS claim then cancelled (cancelled verifikat + gap
explanation per duplicate). Ids are deduped before the loop.
- Bulkbar: the select-all link is hidden when the current view has no
selectable rows; "Markera alla (0)" only wiped the existing selection.
- Invoice dialog open/close handlers (new invoice, self-billed, ROT/RUT
payout) rewrite only their own query keys instead of hardcoding
'/invoices', so the ?status= view write-back survives them.
- /pending: the "Bokfor utkasten" toast CTA is suppressed for kontantmetod
and deferred-booking companies where the invoice list offers no draft
bulk Bokfor (dead end); the neutral hint sentence stays.
Tests: deferred-draft rejection (asserts issueAndBookInvoice never called,
sent invoice in the same batch still books) and duplicate-id dedupe (exactly
one booking call); both fail without the route fix.
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>
* feat(invoices): registrera utan att bokföra + explicit Bokför-steg
Companies where one person registers supplier invoices / sends customer
invoices while ekonomi does the actual bookkeeping had no way to split
the two: under faktureringsmetoden every registration/send booked the
journal entry inline.
- New company setting defer_invoice_booking (default off, accrual only):
registering a supplier invoice or sending/marking-sent a customer
invoice creates NO journal entry.
- New explicit booking routes POST /api/supplier-invoices/[id]/book and
POST /api/invoices/[id]/book: create the registration/revenue entry
afterwards, CAS-guarded against concurrent booking (a lost race
cancels the just-posted voucher with a gap explanation), including
periodisering schedules.
- Detail pages show "Ej bokförd ännu" + a Bokför button for unbooked
accrual invoices; the settings toggle lives under Bokföringsmetod.
- mark-paid needs no changes: both payment flows already route on the
journal-entry link, so an invoice still unbooked when paid gets the
full cash-style entry.
- The mark-sent fail-closed rollback now keys on the same gate so
deferred sends are not rolled back as booking failures.
Fixes#967
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(invoices): harden deferred booking after review
CodeRabbit round on #1040:
- CAS link guards also require a still-bookable status (and uncredited,
customer side) so a concurrent mark-paid/credit cannot end up with a
double-posting registration/revenue entry.
- Settings reads fail closed instead of defaulting to accrual rules.
- Detail pages surface the ACCRUAL_SCHEDULE_FAILED warning instead of
showing plain success, and the customer page no longer stringifies
structured errors into "[object Object]".
- The settings form normalizes defer_invoice_booking to false under
kontantmetoden so a stale flag cannot re-activate on method switch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>