Terminplaner: Aufbewahrungs-Loeschung seitenweise (Grundlagen, verfallen/abgesagt/abgelehnt)
loeschKandidaten liest eine Seite (Standard 100, aelteste Bezugszeit zuerst, optional je Funktion) ohne Gastfelder; die Frist steht in der Abfrage. arbeiteSeiten (Seite lesen, bearbeiten, neu lesen) endet bei leerer Seite, am Deckel (config.termine.loeschDeckel, 2000 je Status und Lauf, Rest an den Folgetagen, gezaehlt als gedeckelt) oder bei einer Seite ohne Fortschritt. verfallen, abgesagt und abgelehnt laufen darueber, unter der Buchungssperre werden Status und Bezugszeit frisch geprueft. taeglicherJob liefert gedeckelt getrennt vom Loeschzaehler. Neue Indizes idx_status_ends und idx_status_updated auf termineBookings (scripts/termine-setup.mjs legt sie an). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2dd9c0dec7
commit
5c95dfc322
8 files changed
+484
-33
No files matched your search
@@ -958,6 +958,59 @@ test('loeschKandidaten: Bezugszeit je Status (verfallen heldUntil, erledigt Term
|
||||
await assert.rejects(B.loeschKandidaten('gehalten', neunzig), TypeError)
|
||||
})
|
||||
|
||||
test('loeschKandidaten: hoechstens limit (Standard 100), aelteste Bezugszeit zuerst, nach Funktion filterbar, ohne Gastfelder', async () => {
|
||||
const mit = (ms) => iso(new Date(JETZT.getTime() + ms))
|
||||
const neunzig = new Date(JETZT.getTime() - 90 * TAG)
|
||||
const nr = (i) => String(i).padStart(3, '0')
|
||||
// 150 alte erledigt; je groesser i, desto spaeter das Terminende; in umgekehrter Reihenfolge angelegt, jede dritte in der Funktion 2
|
||||
for (let i = 149; i >= 0; i -= 1) {
|
||||
seedBuchung(`b_e${nr(i)}`, { status: 'erledigt', endsAt: mit(-91 * TAG + i * MIN), featureId: i % 3 === 0 ? 'f_feature02' : F })
|
||||
}
|
||||
seedBuchung('b_jung', { status: 'erledigt', endsAt: mit(-89 * TAG) })
|
||||
const ids = (liste) => liste.map((doc) => doc.$id)
|
||||
const alle = Array.from({ length: 150 }, (_, i) => `b_e${nr(i)}`)
|
||||
|
||||
aw.resetListCalls()
|
||||
const standard = await B.loeschKandidaten('erledigt', neunzig)
|
||||
assert.deepEqual(ids(standard), alle.slice(0, 100), 'Standard 100, aelteste zuerst')
|
||||
assert.deepEqual(ids(await B.loeschKandidaten('erledigt', neunzig, { limit: 10 })), alle.slice(0, 10))
|
||||
assert.deepEqual(ids(await B.loeschKandidaten('erledigt', neunzig, { limit: 1 })), [alle[0]])
|
||||
const zwei = await B.loeschKandidaten('erledigt', neunzig, { featureId: 'f_feature02' })
|
||||
assert.deepEqual(ids(zwei), alle.filter((_, i) => i % 3 === 0), 'nur die Funktion 2, aelteste zuerst')
|
||||
assert.deepEqual(ids(await B.loeschKandidaten('erledigt', neunzig, { featureId: 'f_feature02', limit: 5 })), alle.filter((_, i) => i % 3 === 0).slice(0, 5))
|
||||
assert.deepEqual(await B.loeschKandidaten('erledigt', neunzig, { featureId: 'f_gibt_es_nicht' }), [])
|
||||
|
||||
// keine Gastfelder: weder Name noch Adresse, nur Kennung, Funktion, Status und die drei Bezugszeiten
|
||||
const erlaubt = new Set(['featureId', 'status', 'endsAt', 'updatedAt', 'heldUntil'])
|
||||
for (const doc of standard) {
|
||||
assert.ok(doc.$id)
|
||||
assert.equal(doc.status, 'erledigt')
|
||||
assert.deepEqual(Object.keys(doc).filter((key) => !key.startsWith('$') && !erlaubt.has(key)), [], `${doc.$id}: nur erlaubte Felder`)
|
||||
assert.equal('gastName' in doc, false)
|
||||
assert.equal('gastEmail' in doc, false)
|
||||
}
|
||||
// die Abfrage sagt es selbst: select ohne Gastfelder, limit, Reihenfolge nach der Bezugszeit
|
||||
const abfrage = aw.listCalls('termineBookings')[0].queries
|
||||
assert.deepEqual(abfrage.find((q) => q.method === 'select').values, ['$id', 'featureId', 'status', 'endsAt', 'updatedAt', 'heldUntil'])
|
||||
assert.deepEqual(abfrage.find((q) => q.method === 'limit').values, [100])
|
||||
assert.deepEqual(abfrage.find((q) => q.method === 'orderAsc'), { method: 'orderAsc', attribute: 'endsAt' })
|
||||
assert.deepEqual(abfrage.find((q) => q.method === 'lessThan'), { method: 'lessThan', attribute: 'endsAt', values: [iso(neunzig)] })
|
||||
|
||||
// Reihenfolge nach der Bezugszeit des Status: verfallen heldUntil, abgesagt updatedAt (Einfuegereihenfolge ist egal)
|
||||
seedBuchung('b_v2', { status: 'verfallen', heldUntil: mit(-60 * STUNDE) })
|
||||
seedBuchung('b_v1', { status: 'verfallen', heldUntil: mit(-70 * STUNDE) })
|
||||
seedBuchung('b_v3', { status: 'verfallen', heldUntil: mit(-50 * STUNDE) })
|
||||
assert.deepEqual(ids(await B.loeschKandidaten('verfallen', new Date(JETZT.getTime() - 48 * STUNDE))), ['b_v1', 'b_v2', 'b_v3'])
|
||||
seedBuchung('b_a2', { status: 'abgesagt', updatedAt: mit(-40 * TAG) })
|
||||
seedBuchung('b_a1', { status: 'abgesagt', updatedAt: mit(-50 * TAG) })
|
||||
assert.deepEqual(ids(await B.loeschKandidaten('abgesagt', new Date(JETZT.getTime() - 30 * TAG))), ['b_a1', 'b_a2'])
|
||||
|
||||
// wie bisher: nicht loeschbare Status und ungueltige limit
|
||||
await assert.rejects(B.loeschKandidaten('bestaetigt', neunzig, { limit: 10 }), TypeError)
|
||||
await assert.rejects(B.loeschKandidaten('gehalten', neunzig), TypeError)
|
||||
for (const limit of [0, -1, 1.5, NaN, '10']) await assert.rejects(B.loeschKandidaten('erledigt', neunzig, { limit }), TypeError, `limit ${limit}`)
|
||||
})
|
||||
|
||||
test('zaehleAnfragen: offene Anfragen einer Funktion (auch ueber 25)', async () => {
|
||||
for (let i = 0; i < 27; i += 1) seedBuchung(`b_anf${String(i).padStart(2, '0')}`, { status: 'angefragt' })
|
||||
seedBuchung('b_best', { status: 'bestaetigt' })
|
||||
|
||||
Reference in new issue
Block a user