Finanzen: Start-Abruf nur bei altem Stand, unlesbare Buchungen ueberspringen, Mail bei Widerruf des Bankzugangs
I1: shouldRunStartupSync; der Abruf 2 Minuten nach dem Start entfaellt, wenn der letzte erfolgreiche Abruf weniger als 5,5 Stunden her ist (Deployments verbrauchten das Tageslimit der Bank). M4: eine unlesbare Buchung wird uebersprungen und gezaehlt, der Abruf endet ok. M10: 401/403 beim Abruf sendet T18 einmal (Stufe 0 in warnedThresholds). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3c5e06723f
commit
ef2ce49669
3 files changed
+168
-25
No files matched your search
@@ -119,12 +119,18 @@ async function runSync({ now, psu }) {
|
||||
const balances = await getBalances(accountUid, { psu })
|
||||
const rawTransactions = await getTransactions(accountUid, { dateFrom, psu })
|
||||
|
||||
// Erst alles umrechnen, dann schreiben: eine kaputte Buchung der Bank bricht ab, bevor etwas gespeichert ist
|
||||
// Erst alles umrechnen, dann schreiben. Eine unlesbare Buchung der Bank (kaputter Betrag, unbekannte Richtung)
|
||||
// wird uebersprungen und gezaehlt, sie blockiert nicht jeden weiteren Abruf
|
||||
const syncedAt = now.toISOString()
|
||||
const docs = new Map()
|
||||
let skipped = 0
|
||||
for (const raw of rawTransactions) {
|
||||
const doc = toTransactionDoc(raw, { accountUid, syncedAt })
|
||||
docs.set(doc.$id, doc)
|
||||
try {
|
||||
const doc = toTransactionDoc(raw, { accountUid, syncedAt })
|
||||
docs.set(doc.$id, doc)
|
||||
} catch {
|
||||
skipped += 1
|
||||
}
|
||||
}
|
||||
|
||||
let latestBookingDate = latest || ''
|
||||
@@ -147,7 +153,7 @@ async function runSync({ now, psu }) {
|
||||
latestBookingDate,
|
||||
lastSyncAt: syncedAt,
|
||||
lastSyncOk: true,
|
||||
lastError: '',
|
||||
lastError: skipped ? `${skipped} Buchung(en) übersprungen (unlesbar).` : '',
|
||||
})
|
||||
return { ...result, ok: true }
|
||||
} catch (err) {
|
||||
@@ -155,7 +161,8 @@ async function runSync({ now, psu }) {
|
||||
const expired = err instanceof EnableBankingError && (err.status === 401 || err.status === 403)
|
||||
const error = expired ? EXPIRED_MESSAGE : errorText(err)
|
||||
try {
|
||||
await saveConnection({ ...(expired ? { status: 'abgelaufen' } : {}), lastSyncOk: false, lastError: error })
|
||||
const saved = await saveConnection({ ...(expired ? { status: 'abgelaufen' } : {}), lastSyncOk: false, lastError: error })
|
||||
if (expired) await notifyRevoked(saved)
|
||||
} catch {
|
||||
// Appwrite selbst gestoert: der Fehler geht trotzdem an den Aufrufer
|
||||
}
|
||||
@@ -163,6 +170,39 @@ async function runSync({ now, psu }) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ablauf oder Widerruf per Mail (T18) melden, hoechstens einmal je Freigabe: Stufe 0 steht danach in
|
||||
* warnedThresholds, dann mailt auch checkBankConsent nicht mehr. War Stufe 0 schon gemeldet (am Ablauftag), bleibt es
|
||||
* bei dieser Mail. Kommt die Mail nicht raus, bleibt die Stufe offen (checkBankConsent versucht es spaeter).
|
||||
*/
|
||||
async function notifyRevoked(connection) {
|
||||
const warned = parseWarned(connection?.warnedThresholds)
|
||||
if (warned.includes(0)) return
|
||||
const validUntilMs = Date.parse(connection?.validUntil ?? '')
|
||||
const result = await sendAdminNotice({
|
||||
template: 'T18',
|
||||
values: {
|
||||
ablauf_text: 'ist abgelaufen oder wurde widerrufen',
|
||||
gueltig_bis: Number.isNaN(validUntilMs) ? 'unbekannt' : formatDe(berlinDate(new Date(validUntilMs))),
|
||||
link: `${config.womsBaseUrl}/finance/einstellungen`,
|
||||
},
|
||||
blocks: { abgelaufen: true },
|
||||
})
|
||||
if (result.sent) await saveConnection({ warnedThresholds: [...new Set([...warned, 0])].sort((a, b) => b - a).join(',') })
|
||||
}
|
||||
|
||||
// Ein Abruf beim Start des Servers wird uebersprungen, wenn der letzte erfolgreiche weniger als 5,5 Stunden her ist:
|
||||
// jedes Deployment startet den Server neu, und die Bank erlaubt nur etwa vier Abrufe ohne Nutzer pro Tag
|
||||
const STARTUP_SYNC_MIN_AGE_MS = 5.5 * 3_600_000
|
||||
|
||||
/** Soll der Abruf nach dem Start des Servers laufen? Nein, wenn der letzte Abruf gelang und noch frisch ist. */
|
||||
export function shouldRunStartupSync(connection, now = new Date()) {
|
||||
if (connection?.lastSyncOk !== true) return true
|
||||
const lastMs = Date.parse(connection.lastSyncAt ?? '')
|
||||
if (Number.isNaN(lastMs)) return true
|
||||
return now.getTime() - lastMs >= STARTUP_SYNC_MIN_AGE_MS
|
||||
}
|
||||
|
||||
/**
|
||||
* Salden und Buchungen abrufen und speichern. psu = { ip, userAgent } nur, wenn ein Mensch den Abruf ausgeloest
|
||||
* hat (zaehlt dann nicht auf das Tageslimit der Bank). Liefert { ok, neu, aktualisiert, geloescht, error? } und
|
||||
|
||||
Reference in new issue
Block a user