Checkin Seite erstellt

This commit is contained in:
2026-01-30 18:59:00 +01:00
parent a1ddaf5a35
commit 32f40124a8
10 changed files with 619 additions and 42 deletions

View File

@@ -1,6 +1,7 @@
// PDF-Generierung Service
const PDFDocument = require('pdfkit');
const QRCode = require('qrcode');
const { db } = require('../database');
const { formatDate, formatDateTime } = require('../helpers/utils');
const { getHolidaysForDateRange } = require('./feiertage-service');
@@ -528,4 +529,72 @@ function generatePDFToBuffer(timesheetId, req) {
});
}
module.exports = { generatePDF, generatePDFToBuffer };
// Check-in/Check-out URL-Basis (wie im Dashboard-Frontend)
function getCheckinBaseUrl(req) {
const baseUrl = `${req.protocol}://${req.get('host')}`;
return baseUrl.replace(/:\d+$/, ':3334');
}
// PDF mit Check-in- und Check-out-QR-Codes (A4)
async function generateCheckinCheckoutQRPDF(req, res) {
const userId = req.session.userId;
if (!userId) {
return res.status(401).send('Nicht angemeldet');
}
const checkinBaseUrl = getCheckinBaseUrl(req);
const checkinUrl = `${checkinBaseUrl}/api/checkin/${userId}`;
const checkoutUrl = `${checkinBaseUrl}/api/checkout/${userId}`;
try {
const [checkinQRBuffer, checkoutQRBuffer] = await Promise.all([
QRCode.toBuffer(checkinUrl, { type: 'png', width: 400, margin: 1 }),
QRCode.toBuffer(checkoutUrl, { type: 'png', width: 400, margin: 1 })
]);
const firstname = (req.session.firstname || '').replace(/\s+/g, '');
const lastname = (req.session.lastname || '').replace(/\s+/g, '');
const namePart = [firstname, lastname].filter(Boolean).join('_') || 'User';
const today = new Date();
const dateStr = today.getFullYear() + '-' +
String(today.getMonth() + 1).padStart(2, '0') + '-' +
String(today.getDate()).padStart(2, '0');
const filename = `Check-in_Check-out_QR_${namePart}_${dateStr}.pdf`;
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
const doc = new PDFDocument({ size: 'A4', margin: 50 });
doc.pipe(res);
const pageWidth = 595.28 - 100;
const qrSize = 160;
const gap = 40;
const left1 = 50 + (pageWidth / 2 - qrSize - gap / 2);
const left2 = 50 + (pageWidth / 2 + gap / 2);
doc.fontSize(18).text('Check-in / Check-out Zeiterfassung', { align: 'center' });
doc.moveDown(1.5);
const topY = doc.y;
doc.image(checkinQRBuffer, left1, topY, { width: qrSize, height: qrSize });
doc.image(checkoutQRBuffer, left2, topY, { width: qrSize, height: qrSize });
doc.fontSize(12).font('Helvetica-Bold');
doc.text('Check-in', left1, topY + qrSize + 8, { width: qrSize, align: 'center' });
doc.text('Check-out', left2, topY + qrSize + 8, { width: qrSize, align: 'center' });
doc.moveDown(2);
doc.font('Helvetica').fontSize(10);
doc.text('Scannen Sie den jeweiligen QR-Code zum Erfassen von Arbeitsbeginn (Check-in) bzw. Arbeitsende (Check-out).', 50, doc.y, { width: pageWidth, align: 'center' });
doc.end();
} catch (err) {
console.error('Fehler beim Generieren des QR-PDFs:', err);
if (!res.headersSent) {
res.status(500).send('Fehler beim Erstellen des PDFs');
}
}
}
module.exports = { generatePDF, generatePDFToBuffer, generateCheckinCheckoutQRPDF };