// Generated, do not edit. sha256:52052b11142a17d483d54341c9f2ba38a354f77829e27fbdc3fddff2dd5437b6 import { describe, it, beforeEach, mock } from 'node:test'; import assert from 'node:assert/strict'; import { createDbHarness } from '../helpers/db-node.mjs'; const harness = createDbHarness(); mock.module('../../server/db.js', { namedExports: harness.exports }); const { createEvent, eventAccountIdsByAsset, eventAssetIdsByAccount, eventDaysByAccount, eventsCountByAccount, eventsNetByAccount, eventsWithoutImportRef, firstTaxEventDate, listEvents, } = await import('../../server/data/events.js'); const { bookReservation, createReservation, deleteReservation, listDueReservations, listReservations, listReservationsForAccount, updateReservation, } = await import('../../server/data/reservations.js'); let eur, bank, spaar; beforeEach(() => { harness.recreate(); harness.exports.run( `INSERT INTO Asset (symbol, name, searchName, kind, unit, subunit, decimals, displayUnit) VALUES ('EUR','Euro','euro','fiat','EUR','cent',2,'unit')`); eur = harness.exports.lastId(); harness.exports.run(`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Bank','bank','bank',0,0,1,NULL)`); bank = harness.exports.lastId(); harness.exports.run(`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Spaar','spaar','bank',0,0,1,NULL)`); spaar = harness.exports.lastId(); }); const rij = (id) => harness.exports.one(`SELECT * FROM Event WHERE id = ?`, [id]); const reservering = (extra = {}) => createReservation({ accountId: bank, assetId: eur, direction: 'out', amount: 50_000, occurredAt: '2026-12-01T00:00:00Z', note: 'aanslag', ...extra, }); const isNietOpen = e => e.key === 'reservations.notOpen'; describe('vastleggen', () => { it('zet een afschrijving op het van-account en een bijboeking op het naar-account', async () => { const uit = await reservering(); const bij = await reservering({ direction: 'in', amount: 10_000 }); assert.deepEqual([rij(uit).type, rij(uit).fromAccountId, rij(uit).toAccountId], ['reservation', bank, null]); assert.deepEqual([rij(bij).fromAccountId, rij(bij).toAccountId], [null, bank]); assert.deepEqual(listReservationsForAccount(bank).map(r => r.id), [uit, bij]); assert.deepEqual(listReservationsForAccount(spaar), []); }); it('weigert een onbekende richting en een reservering zonder account', async () => { await assert.rejects(() => reservering({ direction: 'opzij' }), /direction/); await assert.rejects(() => reservering({ accountId: null }), /account/); }); it('weigert in de datalaag én in de DDL een reservering met twee accounts of met een prijs', async () => { const basis = { assetId: eur, type: 'reservation', occurredAt: '2026-12-01T00:00:00Z', amount: 1, source: 'manual' }; await assert.rejects(() => createEvent({ ...basis, fromAccountId: bank, toAccountId: spaar }), /exactly one account/); await assert.rejects(() => createEvent({ ...basis, fromAccountId: bank, fiatPrice: 1 }), /no price/); assert.throws(() => harness.exports.run( `INSERT INTO Event (assetId, fromAccountId, toAccountId, amount, type, source, occurredAt, createdAt) VALUES (?, ?, ?, 1, 'reservation', 'manual', '2026-12-01T00:00:00Z', '2026-10-23T00:00:00Z')`, [eur, bank, spaar]), /CHECK/); }); }); describe('telt nergens mee zolang hij niet geboekt is', () => { it('blijft buiten saldo, lijsten, importpool en eerste boeking', async () => { await reservering({ occurredAt: '2025-01-01T00:00:00Z' }); assert.equal(eventsNetByAccount(bank, eur, null), 0); assert.equal(eventsCountByAccount(bank, eur, null), 0); assert.deepEqual(listEvents(), []); assert.deepEqual(eventsWithoutImportRef(), []); assert.deepEqual(eventAssetIdsByAccount(bank), []); assert.deepEqual(eventAccountIdsByAsset(eur), []); assert.deepEqual(eventDaysByAccount(bank, eur, '2024-01-01', '2026-01-01'), []); assert.equal(firstTaxEventDate(), null); }); }); describe('vervallen', () => { it('geeft alleen de reserveringen waarvan de datum bereikt is', async () => { const vroeg = await reservering({ occurredAt: '2026-01-01T00:00:00Z' }); await reservering({ occurredAt: '2027-01-01T00:00:00Z' }); assert.deepEqual(listDueReservations('2026-06-01T00:00:00Z').map(r => r.id), [vroeg]); assert.equal(listReservations().length, 2); }); }); describe('boeken', () => { it('maakt van dezelfde rij een verplaatsing met de echte datum en het echte bedrag', async () => { const id = await reservering(); await bookReservation(id, { occurredAt: '2026-12-03T10:00:00Z', amount: 48_000, otherAccountId: null }); const e = rij(id); assert.deepEqual([e.type, e.occurredAt, e.amount, e.fromAccountId, e.toAccountId, e.note], ['transfer', '2026-12-03T10:00:00Z', 48_000, bank, null, 'aanslag']); assert.equal(eventsNetByAccount(bank, eur, null), -48_000, 'nu telt hij wel'); assert.deepEqual(listReservations(), []); }); it('zet een tegenaccount aan de andere kant, ook bij een bijboeking', async () => { const uit = await reservering(); await bookReservation(uit, { occurredAt: '2026-12-01T00:00:00Z', amount: 50_000, otherAccountId: spaar }); assert.deepEqual([rij(uit).fromAccountId, rij(uit).toAccountId], [bank, spaar]); const bij = await reservering({ direction: 'in' }); await bookReservation(bij, { occurredAt: '2026-12-01T00:00:00Z', amount: 50_000, otherAccountId: spaar }); assert.deepEqual([rij(bij).fromAccountId, rij(bij).toAccountId], [spaar, bank]); }); it('weigert een tweede keer boeken, en laat de eerste boeking staan', async () => { const id = await reservering(); await bookReservation(id, { occurredAt: '2026-12-01T00:00:00Z', amount: 50_000 }); await assert.rejects(() => bookReservation(id, { occurredAt: '2026-12-09T00:00:00Z', amount: 1 }), isNietOpen); assert.equal(rij(id).amount, 50_000); }); it('weigert het eigen account als tegenkant, een bedrag van nul en een ongeldige datum', async () => { const id = await reservering(); await assert.rejects(() => bookReservation(id, { occurredAt: '2026-12-01T00:00:00Z', amount: 50_000, otherAccountId: bank }), /another account/); await assert.rejects(() => bookReservation(id, { occurredAt: '2026-12-01T00:00:00Z', amount: 0 }), /amount > 0/); await assert.rejects(() => bookReservation(id, { occurredAt: 'morgen', amount: 1 }), /occurredAt/); assert.equal(rij(id).type, 'reservation', 'en hij staat nog open'); }); }); describe('een gewone boeking is via deze module niet aan te raken', () => { it('weigert boeken, bewerken en verwijderen van een verplaatsing', async () => { const t = await createEvent({ assetId: eur, type: 'transfer', occurredAt: '2026-01-01T00:00:00Z', amount: 100, fromAccountId: bank, toAccountId: spaar, source: 'manual' }); await assert.rejects(() => bookReservation(t, { occurredAt: '2026-01-02T00:00:00Z', amount: 1 }), isNietOpen); await assert.rejects(() => updateReservation(t, { accountId: bank, assetId: eur, direction: 'out', amount: 1, occurredAt: '2026-01-02T00:00:00Z' }), isNietOpen); await assert.rejects(() => deleteReservation(t), isNietOpen); assert.deepEqual([rij(t).type, rij(t).amount], ['transfer', 100]); }); }); describe('bewerken en verwijderen', () => { it('bewerkt bedrag, datum, richting en omschrijving, en blijft een reservering', async () => { const id = await reservering(); await updateReservation(id, { accountId: bank, assetId: eur, direction: 'in', amount: 7, occurredAt: '2027-02-01T00:00:00Z', note: 'teruggave' }); const e = rij(id); assert.deepEqual([e.type, e.amount, e.occurredAt, e.fromAccountId, e.toAccountId, e.note], ['reservation', 7, '2027-02-01T00:00:00Z', null, bank, 'teruggave']); }); it('verwijdert hem zonder boeking', async () => { const id = await reservering(); await deleteReservation(id); assert.ok(!rij(id)); await assert.rejects(() => deleteReservation(id), isNietOpen, 'een tweede keer is er niets meer'); }); });