Buchungskalender: Abschluss – S6 Belegung laedt nur Relevantes, bis-Indizes, 10-s-Speicher

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5.5 committed 2026-10-07 15:25:17 +00:00
1 parent ab838d07bc
commit 17400cac1f
7 files changed
+99 -17

No files matched your search

+16
View File
@@ -39,6 +39,22 @@ test('ueberschneidet: Halboffen, Abreise gleich Anreise ist frei', () => {
assert.equal(bel.ueberschneidet({ von: '2026-11-01', bis: '2026-11-10' }, { von: '2026-11-03', bis: '2026-11-04' }), true)
})
test('Belegung laedt nur Sperren und Anfragen, die nach dem Fensteranfang enden (bis > von)', async () => {
await sp.legeSperreAn({ unterkunftId: 'u1', featureId: 'f1', von: '2026-09-01', bis: '2026-09-10', quelle: 'manuell' })
await sp.legeSperreAn({ unterkunftId: 'u1', featureId: 'f1', von: '2026-11-10', bis: '2026-11-12', quelle: 'manuell' })
anfrage({ status: 'gebucht', von: '2026-09-01', bis: '2026-09-05' })
anfrage({ status: 'gebucht', von: '2026-11-20', bis: '2026-11-22' })
assert.deepEqual((await sp.listeSperren('u1', { bisNach: '2026-11-01' })).map((s) => s.bis), ['2026-11-12'])
assert.equal((await sp.listeSperren('u1')).length, 2)
assert.deepEqual((await sp.listeAnfragenNachStatus('u1', ['gebucht'], { bisNach: '2026-11-01' })).map((a) => a.bis), ['2026-11-22'])
// bis == von: beruehrt das Fenster nicht
assert.equal((await sp.listeSperren('u1', { bisNach: '2026-11-12' })).length, 0)
assert.deepEqual(await bel.belegteBereiche('u1', '2026-11-01', '2026-11-30', { now: NOW }), [
{ von: '2026-11-10', bis: '2026-11-12', quelle: 'manuell' },
{ von: '2026-11-20', bis: '2026-11-22', quelle: 'gebucht' },
])
})
test('Sperre manuell blockiert, Abreisetag nicht', async () => {
await sp.legeSperreAn({ unterkunftId: 'u1', featureId: 'f1', von: '2026-11-10', bis: '2026-11-12', quelle: 'manuell' })
assert.equal(await bel.istFrei('u1', '2026-11-11', '2026-11-13', { now: NOW }), false)
+23 -1
View File
@@ -20,7 +20,7 @@ const K = await import('../server/services/unterkunft/kontext.js')
const T = await import('../server/services/unterkunft/token.js')
const mails = await import('../server/services/unterkunft/mails.js')
const { resetTermineLimitsForTests } = await import('../server/services/termine/limits.js')
const { default: publicRoutes, setzeUhrFuerTests } = await import('../server/routes/publicUnterkunft.js')
const { default: publicRoutes, setzeUhrFuerTests, leereBelegungSpeicherFuerTests } = await import('../server/routes/publicUnterkunft.js')
const app = await startTestApp({ '/api/public/unterkunft/v1': publicRoutes })
after(async () => {
await app.close()
@@ -41,6 +41,7 @@ beforeEach(async () => {
resetTermineLimitsForTests()
mails._aufrufe.length = 0
setzeUhrFuerTests(() => NOW)
leereBelegungSpeicherFuerTests()
aw.seed('portalFeatures', { $id: FEATURE, customerId: 'c1', projectId: 'p1', featureKey: 'unterkunft', siteKey: SITE, state: 'active', enabled: true })
aw.seed('customers', { $id: 'c1', name: 'Mimi', email: 'mimi@example.com' })
aw.seed('websiteProjects', { $id: 'p1', customerId: 'c1', projectName: 'Donau', subdomain: 'donau', liveDomain: 'donau-home.example' })
@@ -113,6 +114,27 @@ test('Belegung: fasst angrenzende Bereiche zusammen, ohne Quelle, auf das Fenste
assert.equal(r.headers.get('access-control-allow-origin'), '*')
})
test('Belegung: Antwort 10 s im Speicher (kein Datenbankzugriff), nach einem Schreiben sofort frisch, danach nach Ablauf frisch', async () => {
aw.seed('ukSperren', { $id: 's1', unterkunftId: 'u1', featureId: FEATURE, von: '2026-11-05', bis: '2026-11-08', quelle: 'manuell' })
const url = `${BASE}/belegung?unterkunft=u1&von=2026-11-01&bis=2026-11-22`
assert.equal((await send('GET', url)).status, 200)
aw.failNext({ collection: 'ukSperren', method: 'GET', status: 500 })
const gemerkt = await send('GET', url)
assert.equal(gemerkt.status, 200, 'aus dem Speicher, kein Zugriff auf ukSperren')
assert.deepEqual(gemerkt.body.belegt, [{ von: '2026-11-05', bis: '2026-11-08' }])
// anderer Zeitraum = anderer Schluessel: trifft den eingeplanten Fehler
assert.equal((await send('GET', `${BASE}/belegung?unterkunft=u1&von=2026-11-02&bis=2026-11-22`)).status, 503)
// Schreiben ueber den Speicher-Pfad macht die Antwort ungueltig
const sp = await import('../server/services/unterkunft/speicher.js')
await sp.legeSperreAn({ unterkunftId: 'u1', featureId: FEATURE, von: '2026-11-10', bis: '2026-11-12', quelle: 'manuell' })
assert.deepEqual((await send('GET', url)).body.belegt, [{ von: '2026-11-05', bis: '2026-11-08' }, { von: '2026-11-10', bis: '2026-11-12' }])
// Ablauf nach 10 s
aw.seed('ukSperren', { $id: 's9', unterkunftId: 'u1', featureId: FEATURE, von: '2026-11-15', bis: '2026-11-16', quelle: 'manuell' })
assert.equal((await send('GET', url)).body.belegt.length, 2)
setzeUhrFuerTests(() => new Date(NOW.getTime() + 11000))
assert.equal((await send('GET', url)).body.belegt.length, 3)
})
test('Belegung: ueber 18 Monate hinaus, kaputte Daten, fremde oder inaktive Unterkunft', async () => {
aw.seed('ukSperren', { $id: 'sz', unterkunftId: 'u1', featureId: FEATURE, von: '2028-04-28', bis: '2028-06-10', quelle: 'manuell' })
const geklemmt = await send('GET', `${BASE}/belegung?unterkunft=u1&von=2028-04-01&bis=2030-01-01`)
+3 -3
View File
@@ -97,7 +97,7 @@ test('Schema: Attribute je Collection wie in der Spezifikation', () => {
test('Schema: Typen und Groessen', () => {
const sizes = {
ukUnterkuenfte: { featureId: 36, name: 120, beschreibung: 500, checkIn: 5, checkOut: 5, icalImporte: 4000, icalExportToken: 64 },
ukUnterkuenfte: { featureId: 36, name: 120, beschreibung: 500, checkIn: 5, checkOut: 5, icalImporte: 8000, icalExportToken: 64 },
ukPreise: { unterkunftId: 36, staffeln: 2000, steuerart: 20, stornobedingungen: 5000 },
ukSperren: { von: 10, bis: 10, quelle: 60, notiz: 200 },
ukAnfragen: {
@@ -145,8 +145,8 @@ test('Schema: Indizes wie in der Spezifikation und nur auf vorhandenen Attribute
const idx = (name) => UNTERKUNFT_COLLECTIONS[name].indexes.map((i) => i.attributes.join('+'))
assert.deepEqual(idx('ukUnterkuenfte'), ['featureId', 'icalExportToken'])
assert.deepEqual(idx('ukPreise'), ['unterkunftId'])
assert.deepEqual(idx('ukSperren'), ['unterkunftId', 'unterkunftId+quelle'])
assert.deepEqual(idx('ukAnfragen'), ['featureId', 'unterkunftId', 'unterkunftId+status', 'status'])
assert.deepEqual(idx('ukSperren'), ['unterkunftId', 'unterkunftId+quelle', 'bis'])
assert.deepEqual(idx('ukAnfragen'), ['featureId', 'unterkunftId', 'unterkunftId+status', 'status', 'bis'])
assert.deepEqual(idx('ukRechnungen'), ['featureId', 'anfrageId', 'featureId+nummer'])
for (const name of NAMES) {
const keys = new Set()