Finanzen: Index auf bankTransactions.status, Vormerkungssuche mit Rueckfall

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-01 15:41:54 +00:00
1 parent 588cc95f5d
commit 75ca8b78c0
4 files changed
+41 -3

No files matched your search

+5 -1
View File
@@ -187,7 +187,11 @@ await ensureCollection(
{ type: 'string', key: 'note', size: 500 },
{ type: 'string', key: 'syncedAt', size: 32 },
],
[{ key: 'idx_booking', type: 'key', attributes: ['bookingDate'] }]
[
{ key: 'idx_booking', type: 'key', attributes: ['bookingDate'] },
// Abruf: vorgemerkte Buchungen (PDNG) suchen
{ key: 'idx_status', type: 'key', attributes: ['status'] },
]
)
// Einstellungen: ein Dokument "main"
+10 -2
View File
@@ -91,9 +91,17 @@ export async function listTransactions({ limit = 1000 } = {}) {
return listDocuments(config.collections.bankTransactions, [Query.orderDesc('bookingDate'), Query.limit(limit)])
}
/** Alle vorgemerkten Buchungen (Status PDNG). */
/**
* Alle vorgemerkten Buchungen (Status PDNG). Die Suche nutzt den Index idx_status; fehlt er in Appwrite noch
* (Setup-Skript nicht erneut gelaufen) oder scheitert die Suche, wird in den gespeicherten Buchungen gefiltert,
* damit die Aufraeumung der Vormerkungen den Abruf nie bricht.
*/
export async function listPendingTransactions() {
return listDocuments(config.collections.bankTransactions, [Query.equal('status', 'PDNG'), Query.limit(1000)])
try {
return await listDocuments(config.collections.bankTransactions, [Query.equal('status', 'PDNG'), Query.limit(1000)])
} catch {
return (await listTransactions()).filter((doc) => doc.status === 'PDNG')
}
}
/** Eine Buchung oder null. */
+17
View File
@@ -385,6 +385,23 @@ test('syncBank: gleiche entry_reference bei Vormerkung und Buchung -> ein Dokume
assert.equal(txDocs().get(docId('same')).status, 'BOOK')
})
test('syncBank: scheitert die Suche nach Vormerkungen, wird im Speicher gefiltert und der Abruf endet trotzdem ok', async () => {
await reset({ transactions: [...nine(), raw({ ref: 'p1', date: '2026-09-30', amount: '12.00', name: 'VORGEMERKT', status: 'PDNG' })] })
await connect()
assert.equal((await syncBank({ now: NOW })).neu, 10)
assert.equal(txDocs().get(docId('p1')).status, 'PDNG')
// die Bank nennt die Vormerkung nicht mehr; die Suche nach status=PDNG (erste Lese-Anfrage an bankTransactions) scheitert
fake.transactions.set(ACCOUNT, nine())
aw.failNext({ collection: config.collections.bankTransactions, method: 'GET', status: 400, message: 'Nachbau: Index status fehlt' })
const result = await syncBank({ now: NOW })
assert.deepEqual(result, { ok: true, neu: 0, aktualisiert: 9, geloescht: 1 })
assert.equal(txDocs().has(docId('p1')), false)
assert.equal(txDocs().size, 9)
assert.equal(connection().lastSyncOk, true)
assert.equal(connection().lastError, '')
})
test('syncBank: Vormerkungen vor dem Abrufzeitraum bleiben, gebuchte Dokumente werden nie gelöscht', async () => {
await reset()
await connect()
+9
View File
@@ -1,5 +1,6 @@
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { schemaKeys } from './support/schema.js'
test('bankTransactions: Attribute der Spec sind im Setup-Skript angelegt', () => {
@@ -28,3 +29,11 @@ test('subscriptions wird weiter aus dem Abo-Setup gelesen', () => {
test('unbekannte Collection scheitert mit klarer Meldung', () => {
assert.throws(() => schemaKeys('gibtEsNicht'), /Collection gibtEsNicht fehlt im Setup-Skript/)
})
test('bankTransactions: Indexe auf bookingDate (Sortierung) und status (Vormerkungen suchen)', () => {
const src = readFileSync(new URL('../scripts/setup-finanzen.mjs', import.meta.url), 'utf8')
const start = src.indexOf("'bankTransactions',")
const block = src.slice(start, src.indexOf("// Einstellungen", start))
assert.match(block, /key: 'idx_booking', type: 'key', attributes: \['bookingDate'\]/)
assert.match(block, /key: 'idx_status', type: 'key', attributes: \['status'\]/)
})