fix(api-v1): propagate underlag when booking via v1 categorize routes (#1564)

The v1 categorize and batch-categorize routes create the journal entry
via createTransactionJournalEntry directly and never ran the shared
underlag propagation, so a booking made through the API-key surface
left the transaction's pinned document unanchored and matched inbox
items unstamped: the same "Underlag saknas" gap #1560 closed for the
dashboard, /book and bulk-book paths, surviving on this one surface.

Both routes now call propagateUnderlagForBookedTransaction after the
CAS write succeeds (only when this request owns the booking; skipped on
partial success and lost CAS races). Best-effort by contract, same as
every other caller: a propagation failure is logged inside the helper
and never fails the booking.

Also adds the attach-after-bulk-book unit test salvaged from the closed
duplicate PR #1559: a document pinned to a bulk-booked transaction
(verifikat anchored via transaction_voucher_links) is anchored against
the samlingsverifikat when attached after the booking.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-13 13:48:01 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent d9dddba682
commit 5769e35869
6 changed files with 198 additions and 0 deletions
@@ -333,4 +333,26 @@ describe('completeInboxItemsForBookedTransaction', () => {
{ created_journal_entry_id: JE2 },
])
})
it('anchors a pinned document against the samlingsverifikat on attach-after-bulk-book', async () => {
// A bulk-booked tx keeps transactions.journal_entry_id null: its verifikat
// hangs off transaction_voucher_links. A document attached AFTER that
// booking (with no inbox item) must still land on the samlingsverifikat:
// voucher-link resolution feeds the pin leg of the propagation.
const { supabase, enqueue, findCalls } = createQueuedMockSupabase()
enqueue({ data: [{ transaction_id: TX1, journal_entry_id: JE2 }] }) // voucher links
enqueue({ data: { document_id: 'doc-pin' } }) // tx pin lookup
enqueue({ data: { journal_entry_id: null } }) // pinned doc unanchored
enqueue({ data: [] }) // no matched inbox items
const result = await completeInboxItemsForBookedTransaction(
supabase as unknown as SupabaseClient,
COMPANY,
TX1,
{ directJournalEntryId: null },
)
expect(result).toBe(JE2)
expect(linkToJournalEntry).toHaveBeenCalledWith(expect.anything(), COMPANY, 'doc-pin', JE2)
expect(findCalls('invoice_inbox_items', 'update')).toEqual([])
})
})