Vertragsverwaltung_Plusfit24/utils/contractPdf.js
2026-02-10 15:29:29 +00:00

205 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const PDFDocument = require('pdfkit');
const fs = require('fs');
const path = require('path');
const Database = require('better-sqlite3');
const db = new Database('plusfit.db', { readonly: true });
/**
* Footer (stabil, ohne Rekursion)
*/
function drawFooter(doc, text) {
const y = doc.page.height - doc.page.margins.bottom + 10;
doc.save();
doc
.fontSize(9)
.fillColor('gray')
.text(
text,
doc.page.margins.left,
y,
{
width: doc.page.width - doc.page.margins.left * 2,
align: 'center'
}
);
doc.restore();
}
module.exports = function createContractPdf(data) {
return new Promise((resolve, reject) => {
try {
/* =========================
Firmendaten laden
========================= */
const company = db.prepare('SELECT * FROM company LIMIT 1').get();
/* =========================
Zielordner sicherstellen
========================= */
const outputDir = path.join(__dirname, '..', 'documents', 'contracts');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const filePath = path.join(
outputDir,
`vertrag_${data.vertragsnummer}.pdf`
);
/* =========================
PDF initialisieren
========================= */
const doc = new PDFDocument({
size: 'A4',
margin: 50
});
const stream = fs.createWriteStream(filePath);
doc.pipe(stream);
const footerText =
`Plusfit · Vertrag ${data.vertragsnummer} · automatisch erstellt`;
/* =========================
HEADER MIT LOGO
========================= */
const logoPath = path.join(
__dirname,
'..',
'public',
'images',
'logo.png'
);
if (fs.existsSync(logoPath)) {
doc.image(logoPath, {
fit: [120, 60],
align: 'left',
valign: 'top'
});
}
doc
.moveDown(1.5)
.fontSize(20)
.text('Mitgliedsvertrag Plusfit', { align: 'center' })
.moveDown(2);
doc.fontSize(12);
/* =========================
VERTRAGSPARTNER (FIRMA)
========================= */
doc.fontSize(11).text('Vertragspartner:', { underline: true });
doc.moveDown(0.5);
if (company) {
doc.text(company.name || 'Plusfit');
if (company.inhaber) doc.text(`Inhaber: ${company.inhaber}`);
const addressLine = [
company.strasse,
company.hausnummer
].filter(Boolean).join(' ');
if (addressLine) doc.text(addressLine);
doc.text(`${company.plz || ''} ${company.ort || ''}`.trim());
if (company.email) doc.text(`E-Mail: ${company.email}`);
if (company.telefon) doc.text(`Telefon: ${company.telefon}`);
} else {
doc.fillColor('red')
.text('⚠️ Firmendaten nicht hinterlegt')
.fillColor('black');
}
doc.moveDown(2);
/* =========================
VERTRAGSDATEN
========================= */
doc.fontSize(12);
doc.text(`Vertragsnummer: ${data.vertragsnummer}`);
doc.text(`Name: ${data.vorname} ${data.nachname}`);
doc.text(`Vertragsart: ${data.vertragName}`);
doc.text(`Laufzeit: ${data.laufzeit} Monate`);
doc.text(`Mitgliedsbeitrag: ${Number(data.betrag).toFixed(2)} € / Monat`);
doc.moveDown();
/* =========================
VERTRAGSERKLÄRUNG
========================= */
doc.text('Vertragserklärung', { underline: true });
doc.moveDown(0.5);
doc.text(
'Der Kunde hat diesen Vertrag durch Anklicken des Buttons ' +
'„Kostenpflichtig verbindlich abschließen“ ausdrücklich angenommen.\n\n' +
'Der Vertrag kommt gemäß §§ 145 ff. BGB durch elektronische Annahme zustande. ' +
'Eine handschriftliche Unterschrift ist nicht erforderlich.'
);
doc.moveDown();
/* =========================
ZAHLUNG
========================= */
doc.text('Zahlungsmodalitäten', { underline: true });
doc.moveDown(0.5);
doc.text(
'Die Zahlung erfolgt monatlich im Voraus per SEPA-Lastschrift ' +
'von dem vom Kunden angegebenen Bankkonto.'
);
doc.moveDown();
/* =========================
WIDERRUFSBELEHRUNG
========================= */
doc.text('Widerrufsbelehrung', { underline: true });
doc.moveDown(0.5);
doc.text(
'Sie haben das Recht, diesen Vertrag binnen 14 Tagen ohne Angabe von Gründen zu widerrufen. ' +
'Die Frist beginnt mit dem Tag des Vertragsabschlusses.'
);
doc.moveDown(2);
/* =========================
ABSCHLUSSINFO
========================= */
const datum = new Date(data.datum).toLocaleDateString('de-DE');
doc.text(`Vertragsabschluss am: ${datum}`);
const ipText = data.ip && data.ip !== '::1' ? data.ip : 'nicht gespeichert (Datenschutz)';
doc.text(`IP-Adresse bei Abschluss: ${ipText}`);
doc.moveDown(2);
doc.text(
'Dieser Vertrag wurde elektronisch abgeschlossen. ' +
'Gemäß § 126a BGB ist keine handschriftliche Unterschrift erforderlich.',
{ italic: true }
);
/* =========================
FOOTER (nur einmal, stabil)
========================= */
drawFooter(doc, footerText);
doc.end();
stream.on('finish', () => resolve(filePath));
stream.on('error', reject);
} catch (err) {
reject(err);
}
});
};