This commit is contained in:
2026-02-02 19:12:40 +01:00
parent c6421049c8
commit 952c353118
17 changed files with 982 additions and 513 deletions

View File

@@ -530,18 +530,56 @@ function generatePDFToBuffer(timesheetId, req) {
}
// 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');
function getCheckinBaseUrl(req, callback) {
// Versuche Root URL aus Datenbank zu laden
db.get('SELECT checkin_root_url FROM system_options WHERE id = 1', (err, options) => {
if (err) {
console.warn('Fehler beim Laden der Root URL, verwende Fallback:', err);
}
let checkinBaseUrl = null;
if (options && options.checkin_root_url && options.checkin_root_url.trim() !== '') {
checkinBaseUrl = options.checkin_root_url.trim();
// Stelle sicher, dass kein trailing slash vorhanden ist
checkinBaseUrl = checkinBaseUrl.replace(/\/+$/, '');
}
// Fallback: Konstruiere URL aus Request (Port 3334 für Check-in)
if (!checkinBaseUrl) {
const baseUrl = `${req.protocol}://${req.get('host')}`;
checkinBaseUrl = baseUrl.replace(/:\d+$/, ':3334');
}
callback(checkinBaseUrl);
});
}
// PDF mit Check-in- und Check-out-QR-Codes (A4)
async function generateCheckinCheckoutQRPDF(req, res) {
// urlType: 'internal' oder 'external'
async function generateCheckinCheckoutQRPDF(req, res, urlType = 'internal') {
const userId = req.session.userId;
if (!userId) {
return res.status(401).send('Nicht angemeldet');
}
const checkinBaseUrl = getCheckinBaseUrl(req);
let checkinBaseUrl;
if (urlType === 'external') {
// Externe URL: Lade aus Datenbank
checkinBaseUrl = await new Promise((resolve) => {
getCheckinBaseUrl(req, resolve);
});
} else {
// Interne URL: Konstruiere aus Request (Port 3334)
const baseUrl = `${req.protocol}://${req.get('host')}`;
if (baseUrl.match(/:\d+$/)) {
checkinBaseUrl = baseUrl.replace(/:\d+$/, ':3334');
} else {
const url = new URL(baseUrl);
checkinBaseUrl = `${url.protocol}//${url.hostname}:3334`;
}
}
const checkinUrl = `${checkinBaseUrl}/api/checkin/${userId}`;
const checkoutUrl = `${checkinBaseUrl}/api/checkout/${userId}`;
@@ -554,11 +592,12 @@ async function generateCheckinCheckoutQRPDF(req, res) {
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 urlTypeLabel = urlType === 'external' ? 'Extern' : 'Intern';
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`;
const filename = `Check-in_Check-out_QR_${urlTypeLabel}_${namePart}_${dateStr}.pdf`;
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('X-Content-Type-Options', 'nosniff');
@@ -573,7 +612,10 @@ async function generateCheckinCheckoutQRPDF(req, res) {
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' });
const title = urlType === 'external'
? 'Check-in / Check-out Zeiterfassung (Externe URLs)'
: 'Check-in / Check-out Zeiterfassung (Interne URLs)';
doc.fontSize(18).text(title, { align: 'center' });
doc.moveDown(1.5);
const topY = doc.y;