4bc007cdeb
* fix(reports): periodisk sammanställning nets a stornoed or corrected EU invoice voucher (#2351) The PS reads entries with status posted or reversed, so a stornoed EU invoice voucher kept its 3308/3108 credit while the storno that nets it was dropped: its source_type is 'storno' and no register row points at it. A makulerad EU sale was over-reported while the account-based ruta 39 was zero. Which invoice explains an entry is now resolved by one composed helper, getInvoicesExplainingJournalEntries (lib/core/bookkeeping/ journal-entry-references.ts): the engine's own source_id, the invoice-side rows, and the rättelse chain through correction_of_id / reverses_id, walked upwards under the MAX_CHAIN_WALK cap correction-chain.ts already uses. Parents outside the batch are fetched by id, company-scoped. The link columns are followed rather than the storno's copied source_id because correctEntry() copies none onto its storno or correction, and a storno's copied source_id is polymorphic (a bank row on a bank booking). getInvoiceReferencesForJournalEntries (the RPC mirror behind the underlag surfaces) is unchanged: storno and correction are not doc-requiring source types, so those surfaces have no such hole. - INVOICE_SOURCED_ENTRY_TYPES / LINK_LOOKUP_CHUNK move to the helper module (the set now names every engine type whose source_id is an invoice). - PS: one resolver call; reverses_id, correction_of_id in the select; the ZERO_NET_EXCLUDED text names makulering beside kreditfaktura. - Tests: resolver cases (chain inheritance, out-of-batch fetch, own link wins, mirror, cycle, cap) and PS cases (the issue's storno nets to ZERO_NET_EXCLUDED, rättelse chain, later-period storno, mirror, linked import, gone invoice). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LvMaHcTnwAfxzgYD1fGYX1 * fix(bookkeeping): PR #2354 review: bound in-batch chain propagation at MAX_CHAIN_WALK getInvoicesExplainingJournalEntries attributed an in-batch chain of stornos/corrections all the way down through a recursive assign over waitingOn, while parents fetched from outside the batch stopped at MAX_CHAIN_WALK. The two paths now agree: every attribution carries its depth from the root (0 for an entry resolved by its own source_id or invoice-side link), propagation is an explicit queue instead of recursion, and a descendant more than MAX_CHAIN_WALK links below the root resolves to no invoice, both when it inherits from an already attributed parent and when it is reached by propagation. Test: an in-batch chain of MAX_CHAIN_WALK + 1 links, in both batch orders, attributes the links within the cap and not the one beyond it, with no parent fetch. 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>