Files
accounted/lib/bookkeeping/__tests__/fiscal-year-gaps.test.ts
T
c62321988b feat(reconciliation,bokslut): underlag on a balansdag + persisted closing checklist (Reko bilagor, PR 2 + PR 3) (#1873)
* feat(reconciliation): underlag on a balansdag, the files behind a sign-off (Reko bilagor, PR 2)

A konsult attaches the kontoutdrag, engagemangsbesked or reskontralista an
account was reconciled against to (account_key, through_date), before or
after the sign-off, from every account body on the Avstämning page. Rows
live in account_reconciliation_attachments (append-only, removal stamp by
trigger, RLS like account_reconciliations), bytes in the documents bucket
under the company prefix so its RLS applies unchanged, and the full
archive copies them into bilagor/ with a hash manifest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvFveUpbdPBXdm7f5FEYoz

* fix(reconciliation): literal selects and payload in the attachments store so the phantom-column scanner can read them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvFveUpbdPBXdm7f5FEYoz

* feat(bokslut): persisted closing checklist and missing-fiscal-year warning (Reko bilagor, PR 3) (#1867)

* feat(bokslut): persisted closing checklist and missing-fiscal-year warning (Reko bilagor, PR 3)

The bokslut checklist is a catalogue in code with one state row per period
(bokslut_checklist_items): the steps the system can judge (sign-offs through
balansdagen, reskontra tie-outs, drafts, voucher gaps, trial balance) are
computed live and a stored row only overrides them; the manual steps are
the konsult's ticks, with who and when. It sits on the wizard's Kontroll
step and is dumped into the full archive.

A hole between fiscal years (one-file SIE migrations) is now named on the
bokslut readiness screen and on the import result screen, where the next
file is one click away. Non-adjacent period links are #1849's fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvFveUpbdPBXdm7f5FEYoz

* fix(bokslut): count unexplained voucher gaps, literal select and payload for the checklist store

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvFveUpbdPBXdm7f5FEYoz

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
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>
2026-08-25 09:34:05 +02:00

39 lines
1.8 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { describeFiscalYearGap, findFiscalYearGaps } from '../fiscal-year-gaps'
const p = (id: string, start: string, end: string) => ({ id, name: `Räkenskapsår ${start.slice(0, 4)}`, period_start: start, period_end: end })
describe('findFiscalYearGaps', () => {
it('finds a missing calendar year between two periods regardless of input order', () => {
const gaps = findFiscalYearGaps([p('c', '2026-01-01', '2026-12-31'), p('a', '2024-01-01', '2024-12-31')])
expect(gaps).toHaveLength(1)
expect(gaps[0]).toMatchObject({ missing_from: '2025-01-01', missing_to: '2025-12-31' })
expect(gaps[0].after.id).toBe('a')
expect(gaps[0].before.id).toBe('c')
})
it('reports nothing for adjacent periods, broken years included, and for a single period', () => {
expect(findFiscalYearGaps([p('a', '2024-07-01', '2025-06-30'), p('b', '2025-07-01', '2026-06-30')])).toEqual([])
expect(findFiscalYearGaps([p('a', '2024-01-01', '2024-12-31')])).toEqual([])
expect(findFiscalYearGaps([])).toEqual([])
})
it('ignores overlaps and finds every hole in a longer chain', () => {
const gaps = findFiscalYearGaps([
p('a', '2021-01-01', '2021-12-31'),
p('b', '2021-06-01', '2022-05-31'),
p('c', '2024-01-01', '2024-12-31'),
p('d', '2027-01-01', '2027-12-31'),
])
expect(gaps.map((g) => [g.missing_from, g.missing_to])).toEqual([
['2022-06-01', '2023-12-31'],
['2025-01-01', '2026-12-31'],
])
})
it('describes a gap in Swedish with both neighbours named', () => {
const [gap] = findFiscalYearGaps([p('a', '2024-01-01', '2024-12-31'), p('c', '2026-01-01', '2026-12-31')])
expect(describeFiscalYearGap(gap)).toMatch(/2025-01-01 till 2025-12-31 \(mellan Räkenskapsår 2024 och Räkenskapsår 2026\)/)
})
})