const express = require("express"); const Database = require("better-sqlite3"); const validateSepa = require("../utils/sepaValidator"); const { encrypt } = require("../utils/crypto"); const generateVertragsnummer = require("../utils/vertragsnummer"); const createContractPdf = require("../utils/contractPdf"); const sendContractMail = require("../utils/sendContractMail"); const sendAdminMail = require("../utils/sendAdminMail"); const router = express.Router(); const db = new Database("plusfit.db"); /* ========================= Helper ========================= */ function loadActiveContracts() { return db .prepare( ` SELECT * FROM vertragsarten WHERE aktiv = 1 ORDER BY betrag ASC `, ) .all(); } /* ========================= GET /register ========================= */ router.get("/", (req, res) => { const vertragId = req.query.vertrag || null; const vertraege = loadActiveContracts(); // Prüfen ob Vertrag existiert const selected = vertraege.find((v) => v.id == vertragId); return res.render("register", { vertragsarten: vertraege, selectedVertrag: selected ? selected.id : null, selectedVertragData: selected || null, formData: {}, }); }); /* ========================= POST /register/create ========================= */ router.post("/create", async (req, res) => { const u = req.body; const vertragsarten = loadActiveContracts(); /* ========================= Vertragsdaten laden ========================= */ const contractData = db .prepare( ` SELECT name, laufzeit, betrag FROM vertragsarten WHERE id = ? AND aktiv = 1 `, ) .get(u.vertragsvariante); if (!contractData) { return res.render("register", { vertragsarten, selectedVertrag: u.vertragsvariante, error: "Vertragsdaten konnten nicht geladen werden.", formData: u, }); } /* ========================= Pflicht-Zustimmungen ========================= */ if (!u.agreeConsent || !u.agreeAgb || !u.agreeSepa) { return res.render("register", { vertragsarten, selectedVertrag: u.vertragsvariante, error: "Bitte bestätige alle rechtlichen Hinweise, um fortzufahren.", formData: u, }); } /* ========================= Formale SEPA-Prüfung ========================= */ const sepaError = validateSepa({ ibanValue: u.iban, bic: u.bic, mandatsreferenz: u.mandatsreferenz, }); if (sepaError) { return res.render("register", { vertragsarten, selectedVertrag: u.vertragsvariante, error: sepaError, formData: u, }); } /* ========================= Logische Prüfungen ========================= */ const mandatsExists = db .prepare( ` SELECT id FROM users WHERE mandatsreferenz = ? `, ) .get(u.mandatsreferenz); if (mandatsExists) { return res.render("register", { vertragsarten, selectedVertrag: u.vertragsvariante, error: "Diese Mandatsreferenz ist bereits vergeben.", formData: u, }); } /* ========================= Vertrags- & Zustimmungsdaten ========================= */ const vertragsnummer = generateVertragsnummer(); const zustimmungsDatum = new Date().toISOString(); const zustimmungsIp = ( req.headers["x-forwarded-for"] || req.socket?.remoteAddress || "" ) .split(",")[0] .trim(); const vertragsversion = "v1.0"; const widerrufBis = new Date(); widerrufBis.setDate(widerrufBis.getDate() + 14); /* ========================= Verschlüsselung ========================= */ const ibanEncrypted = encrypt(u.iban); const bicEncrypted = encrypt(u.bic); /* ========================= SPEICHERN ========================= */ db.prepare( ` INSERT INTO users ( vertragsnummer, vertragsvariante, vorname, nachname, strasse, hausnummer, plz, ort, land, mobil, telefon, email, kontoinhaber, iban, bic, mandatsreferenz, zustimmung_agb, zustimmung_sepa, zustimmung_einverstaendnis, zustimmung_datum, zustimmung_ip, vertragsversion, widerruf_moeglich_bis, status, gesperrt ) VALUES ( ?,?, ?,?, ?,?,?,?,?, ?,?,?, ?,?,?,?, ?,?,?,?, ?,?, ?,?, 0 ) `, ).run( vertragsnummer, u.vertragsvariante, u.vorname, u.nachname, u.strasse, u.hausnummer, u.plz, u.ort, u.land, u.mobil, u.telefon, u.email, u.kontoinhaber, ibanEncrypted, bicEncrypted, u.mandatsreferenz, u.agreeAgb ? 1 : 0, u.agreeSepa ? 1 : 0, u.agreeConsent ? 1 : 0, zustimmungsDatum, zustimmungsIp, vertragsversion, widerrufBis.toISOString(), "aktiv", ); /* ========================= Vertrags-PDF ========================= */ const pdfPath = await createContractPdf({ vertragsnummer, vorname: u.vorname, nachname: u.nachname, vertragName: contractData.name, laufzeit: contractData.laufzeit, betrag: contractData.betrag, datum: zustimmungsDatum, ip: zustimmungsIp, }); /* ========================= Vertragsmail ========================= */ await sendContractMail({ email: u.email, vorname: u.vorname, vertragsnummer, vertragName: contractData.name, betrag: contractData.betrag, datum: zustimmungsDatum, pdfPath, }); await sendAdminMail({ vertragsnummer, vorname: u.vorname, nachname: u.nachname, email: u.email, vertragName: contractData.name, betrag: contractData.betrag, datum: zustimmungsDatum, ip: zustimmungsIp, }); /* ========================= ERFOLG ========================= */ return res.render("registerSuccess", { vertragsnummer }); }); module.exports = router;