From 0ab8fb0aafaf4ef53260a9ccaa5f4b5b9b2d0bc6 Mon Sep 17 00:00:00 2001 From: ah-admin Date: Sun, 4 Oct 2026 17:29:20 +0200 Subject: [PATCH] v1.27a: strikte Ablesedatum-Validierung (datumGueltig, kein Monatsueberlauf) --- kimi.md | 6 +++++- server/src/index.js | 4 ++-- server/src/zaehlerVerlauf.js | 21 ++++++++++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/kimi.md b/kimi.md index c8ab7de..b4ee12d 100644 --- a/kimi.md +++ b/kimi.md @@ -195,7 +195,11 @@ Default heute); stand_am + erster Verlaufseintrag (erstbefund) nutzen das Datum. Frontend ZaehlerDialog: Haus-Textfeld entfernt – Haus folgt der Wohneinheit, nur bei „Allgemeinzähler (ohne Wohnung)" erscheint eine Haus-Auswahl (buildings-Select, Anzeige b.adresse). Ablesedatum (type=date, Default heute, -Pflicht) nur bei Neuanlage; Frontend wandelt YYYY-MM-DD → TT.MM.JJJJ. +Pflicht) nur bei Neuanlage; Frontend wandelt YYYY-MM-DD → TT.MM.JJJJ. WICHTIG: parseDatum ist ein +lenient Parser (Überlauf 32.13. → Feb Folgejahr!) – für Benutzereingaben +zusätzlich zaehlerVerlauf.datumGueltig (Exaktheits-Roundtrip, nur +dd.mm.yyyy/yyyy-mm-dd) – eingesetzt in POST /api/meters und +POST /api/meters/:id/readings. **Erledigt 04.10. (v1.26):** Haus-Formular ohne Namensfeld, Adresse in Einzelfelder. buildings um strasse/hausnummer/plz/ort/lage/wohnflaeche/grundstuecksflaeche diff --git a/server/src/index.js b/server/src/index.js index f47b418..ba7f5d2 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -558,7 +558,7 @@ app.post('/api/meters', auth, adminOnly, async (req, res, next) => { const standZahl = Number(stand) if (!Number.isFinite(standZahl) || standZahl < 0) return res.status(400).json({ fehler: 'Ungültiger Zählerstand.' }) const datum = String(standAm || '').trim() || deutschesDatum() - if (!zaehlerVerlauf.parseDatum(datum)) return res.status(400).json({ fehler: 'Ungültiges Ablesedatum.' }) + if (!zaehlerVerlauf.datumGueltig(datum)) return res.status(400).json({ fehler: 'Ungültiges Ablesedatum.' }) // Wohnung angegeben → Haus aus der Wohnung ableiten; sonst muss das Haus im Body stehen let einheitId = unitId ? String(unitId) : null let haus = String(building || '').trim() @@ -657,7 +657,7 @@ app.post('/api/meters/:id/readings', auth, async (req, res, next) => { const standZahl = Number(stand) if (!Number.isFinite(standZahl) || standZahl < 0) return res.status(400).json({ fehler: 'Ungültiger Zählerstand.' }) const datum = String(standAm || '').trim() || deutschesDatum() - if (!zaehlerVerlauf.parseDatum(datum)) return res.status(400).json({ fehler: 'Ungültiges Ablesedatum.' }) + if (!zaehlerVerlauf.datumGueltig(datum)) return res.status(400).json({ fehler: 'Ungültiges Ablesedatum.' }) const { eintrag, anomalie, grund } = await zaehlerVerlauf.standEintragen({ meter: m, stand: standZahl, standAm: datum, erfasstVon: req.user.name, quelle: req.user.rolle === 'verwaltung' ? 'manuel' : 'mieter', diff --git a/server/src/zaehlerVerlauf.js b/server/src/zaehlerVerlauf.js index 8f69f05..f6e383d 100644 --- a/server/src/zaehlerVerlauf.js +++ b/server/src/zaehlerVerlauf.js @@ -29,6 +29,25 @@ function parseDatum(s) { return Number.isNaN(fallback.getTime()) ? null : fallback } +/** Strikte Prüfung für Benutzereingaben: nur dd.mm.yyyy / yyyy-mm-dd und das + * Datum muss exakt existieren (kein Überlauf wie 32.13. → Feb des Folgejahres). */ +function datumGueltig(s) { + const str = String(s || '').trim() + const d = parseDatum(str) + if (!d) return false + const iso = /^(\d{4})-(\d{2})-(\d{2})$/.exec(str) + if (iso) { + return d.getUTCFullYear() === Number(iso[1]) && d.getUTCMonth() === Number(iso[2]) - 1 && + d.getUTCDate() === Number(iso[3]) + } + const de = /^(\d{1,2})\.(\d{1,2})\.(\d{4})$/.exec(str) + if (de) { + return d.getUTCFullYear() === Number(de[3]) && d.getUTCMonth() === Number(de[2]) - 1 && + d.getUTCDate() === Number(de[1]) + } + return false +} + const tageZwischen = (a, b) => Math.round((b - a) / 86400000) const runde = (n, stellen = 1) => Math.round(n * 10 ** stellen) / 10 ** stellen @@ -171,4 +190,4 @@ async function erstbefundFehlende() { if (rows.length) console.log(`[api] Zählerverlauf: ${rows.length} Erstbefund(e) ergänzt`) } -module.exports = { pruefeAnomalie, verlaufLaden, standEintragen, erstbefundFehlende, mapReading, parseDatum } +module.exports = { pruefeAnomalie, verlaufLaden, standEintragen, erstbefundFehlende, mapReading, parseDatum, datumGueltig }