DSGVO und LDAP fix
This commit is contained in:
@@ -4,7 +4,7 @@ const PDFDocument = require('pdfkit');
|
||||
const QRCode = require('qrcode');
|
||||
const { db } = require('../database');
|
||||
const { formatDate, formatDateTime } = require('../helpers/utils');
|
||||
const { getHolidaysForDateRange } = require('./feiertage-service');
|
||||
const { getHolidaysWithNamesForDateRange } = require('./feiertage-service');
|
||||
|
||||
// Kalenderwoche berechnen
|
||||
function getCalendarWeek(dateStr) {
|
||||
@@ -67,14 +67,14 @@ function generatePDF(timesheetId, req, res) {
|
||||
return new Date(a.date) - new Date(b.date);
|
||||
});
|
||||
|
||||
// Feiertage für die Woche laden (8h pro Feiertag; Arbeit an Feiertag = Überstunden)
|
||||
getHolidaysForDateRange(timesheet.week_start, timesheet.week_end)
|
||||
.then((holidaySet) => {
|
||||
// Feiertage für die Woche laden (mit Namen für PDF-Ausgabe)
|
||||
const arbeitstage = timesheet.arbeitstage || 5;
|
||||
const fullDayHours = timesheet.wochenstunden > 0 && arbeitstage > 0 ? timesheet.wochenstunden / arbeitstage : 8;
|
||||
getHolidaysWithNamesForDateRange(timesheet.week_start, timesheet.week_end)
|
||||
.then(({ holidaySet, holidayNames }) => {
|
||||
let holidayHours = 0;
|
||||
const start = new Date(timesheet.week_start);
|
||||
const end = new Date(timesheet.week_end);
|
||||
const arbeitstage = timesheet.arbeitstage || 5;
|
||||
const fullDayHours = timesheet.wochenstunden > 0 && arbeitstage > 0 ? timesheet.wochenstunden / arbeitstage : 8;
|
||||
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
|
||||
const day = d.getDay();
|
||||
if (day >= 1 && day <= 5) {
|
||||
@@ -82,10 +82,10 @@ function generatePDF(timesheetId, req, res) {
|
||||
if (holidaySet.has(dateStr)) holidayHours += fullDayHours;
|
||||
}
|
||||
}
|
||||
return { holidaySet, holidayHours };
|
||||
return { holidaySet, holidayNames, holidayHours };
|
||||
})
|
||||
.catch(() => ({ holidaySet: new Set(), holidayHours: 0 }))
|
||||
.then(({ holidaySet, holidayHours }) => {
|
||||
.catch(() => ({ holidaySet: new Set(), holidayNames: new Map(), holidayHours: 0 }))
|
||||
.then(({ holidaySet, holidayNames, holidayHours }) => {
|
||||
const doc = new PDFDocument({ margin: 50 });
|
||||
|
||||
// Prüfe ob inline angezeigt werden soll (für Vorschau)
|
||||
@@ -164,16 +164,48 @@ function generatePDF(timesheetId, req, res) {
|
||||
doc.moveTo(50, y).lineTo(430, y).stroke();
|
||||
doc.moveDown(0.5);
|
||||
|
||||
// Zeilen: Einträge + Feiertage ohne Eintrag, nach Datum sortiert
|
||||
const allRows = [];
|
||||
entries.forEach((e) => allRows.push({ type: 'entry', entry: e }));
|
||||
holidaySet.forEach((dateStr) => {
|
||||
if (!entriesByDate[dateStr]) {
|
||||
allRows.push({ type: 'holiday', date: dateStr, holidayName: holidayNames.get(dateStr) || 'Feiertag' });
|
||||
}
|
||||
});
|
||||
allRows.sort((a, b) => {
|
||||
const dateA = a.type === 'entry' ? a.entry.date : a.date;
|
||||
const dateB = b.type === 'entry' ? b.entry.date : b.date;
|
||||
return dateA.localeCompare(dateB);
|
||||
});
|
||||
|
||||
// Tabellen-Daten
|
||||
doc.font('Helvetica');
|
||||
let totalHours = 0;
|
||||
let vacationHours = 0; // Urlaubsstunden für Überstunden-Berechnung
|
||||
|
||||
entries.forEach((entry) => {
|
||||
allRows.forEach((row) => {
|
||||
if (row.type === 'holiday') {
|
||||
y = doc.y;
|
||||
x = 50;
|
||||
const rowData = [formatDate(row.date), '-', '-', '-', fullDayHours.toFixed(2) + ' h (Feiertag)'];
|
||||
rowData.forEach((data, i) => {
|
||||
doc.text(data, x, y, { width: colWidths[i], align: 'left' });
|
||||
x += colWidths[i];
|
||||
});
|
||||
doc.moveDown(0.2);
|
||||
doc.fontSize(9).font('Helvetica-Oblique');
|
||||
doc.text('Feiertag: ' + row.holidayName, 60, doc.y, { width: 360 });
|
||||
doc.fontSize(10);
|
||||
doc.moveDown(0.5);
|
||||
y = doc.y;
|
||||
doc.moveTo(50, y).lineTo(430, y).stroke();
|
||||
doc.moveDown(0.3);
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = row.entry;
|
||||
y = doc.y;
|
||||
x = 50;
|
||||
|
||||
// Basis-Zeile
|
||||
const rowData = [
|
||||
formatDate(entry.date),
|
||||
entry.start_time || '-',
|
||||
@@ -224,6 +256,9 @@ function generatePDF(timesheetId, req, res) {
|
||||
|
||||
// Überstunden und Urlaub anzeigen
|
||||
const overtimeInfo = [];
|
||||
if (holidaySet.has(entry.date)) {
|
||||
overtimeInfo.push('Feiertag: ' + (holidayNames.get(entry.date) || 'Feiertag'));
|
||||
}
|
||||
if (entry.overtime_taken_hours && parseFloat(entry.overtime_taken_hours) > 0) {
|
||||
overtimeInfo.push(`Überstunden genommen: ${parseFloat(entry.overtime_taken_hours).toFixed(2)} h`);
|
||||
}
|
||||
@@ -243,28 +278,20 @@ function generatePDF(timesheetId, req, res) {
|
||||
}
|
||||
|
||||
// Urlaub hat Priorität - wenn Urlaub, zähle nur Urlaubsstunden, nicht zusätzlich Arbeitsstunden
|
||||
const arbeitstage = timesheet.arbeitstage || 5;
|
||||
const fullDayHours = timesheet.wochenstunden > 0 && arbeitstage > 0 ? timesheet.wochenstunden / arbeitstage : 8;
|
||||
if (entry.vacation_type === 'full') {
|
||||
vacationHours += fullDayHours; // Ganzer Tag = (Wochenarbeitszeit / Arbeitstage) Stunden
|
||||
// Bei vollem Tag Urlaub werden keine Arbeitsstunden gezählt
|
||||
vacationHours += fullDayHours;
|
||||
} else if (entry.vacation_type === 'half') {
|
||||
vacationHours += fullDayHours / 2; // Halber Tag = (Wochenarbeitszeit / Arbeitstage) / 2 Stunden
|
||||
// Bei halbem Tag Urlaub können noch Arbeitsstunden vorhanden sein
|
||||
vacationHours += fullDayHours / 2;
|
||||
if (entry.total_hours) {
|
||||
totalHours += entry.total_hours;
|
||||
}
|
||||
} else {
|
||||
// Kein Urlaub - zähle Arbeitsstunden; an Feiertagen zählt jede Stunde als Überstunde (8h Feiertag + Arbeit)
|
||||
if (entry.total_hours) {
|
||||
totalHours += entry.total_hours;
|
||||
}
|
||||
}
|
||||
// Feiertag: 8h sind über holidayHours erfasst; gearbeitete Stunden oben bereits zu totalHours addiert
|
||||
|
||||
doc.moveDown(0.5);
|
||||
|
||||
// Trennlinie zwischen Einträgen
|
||||
y = doc.y;
|
||||
doc.moveTo(50, y).lineTo(430, y).stroke();
|
||||
doc.moveDown(0.3);
|
||||
@@ -347,24 +374,24 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
return new Date(a.date) - new Date(b.date);
|
||||
});
|
||||
|
||||
getHolidaysForDateRange(timesheet.week_start, timesheet.week_end)
|
||||
.then((holidaySet) => {
|
||||
const arbeitstageBuf = timesheet.arbeitstage || 5;
|
||||
const fullDayHoursBuf = timesheet.wochenstunden > 0 && arbeitstageBuf > 0 ? timesheet.wochenstunden / arbeitstageBuf : 8;
|
||||
getHolidaysWithNamesForDateRange(timesheet.week_start, timesheet.week_end)
|
||||
.then(({ holidaySet, holidayNames }) => {
|
||||
let holidayHours = 0;
|
||||
const start = new Date(timesheet.week_start);
|
||||
const end = new Date(timesheet.week_end);
|
||||
const arbeitstage = timesheet.arbeitstage || 5;
|
||||
const fullDayHours = timesheet.wochenstunden > 0 && arbeitstage > 0 ? timesheet.wochenstunden / arbeitstage : 8;
|
||||
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
|
||||
const day = d.getDay();
|
||||
if (day >= 1 && day <= 5) {
|
||||
const dateStr = d.toISOString().split('T')[0];
|
||||
if (holidaySet.has(dateStr)) holidayHours += fullDayHours;
|
||||
if (holidaySet.has(dateStr)) holidayHours += fullDayHoursBuf;
|
||||
}
|
||||
}
|
||||
return { holidaySet, holidayHours };
|
||||
return { holidaySet, holidayNames, holidayHours };
|
||||
})
|
||||
.catch(() => ({ holidaySet: new Set(), holidayHours: 0 }))
|
||||
.then(({ holidayHours }) => {
|
||||
.catch(() => ({ holidaySet: new Set(), holidayNames: new Map(), holidayHours: 0 }))
|
||||
.then(({ holidaySet, holidayNames, holidayHours }) => {
|
||||
const doc = new PDFDocument({ margin: 50 });
|
||||
const buffers = [];
|
||||
|
||||
@@ -405,15 +432,48 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
doc.moveTo(50, y).lineTo(430, y).stroke();
|
||||
doc.moveDown(0.5);
|
||||
|
||||
// Zeilen: Einträge + Feiertage ohne Eintrag, nach Datum sortiert
|
||||
const allRowsBuf = [];
|
||||
entries.forEach((e) => allRowsBuf.push({ type: 'entry', entry: e }));
|
||||
holidaySet.forEach((dateStr) => {
|
||||
if (!entriesByDate[dateStr]) {
|
||||
allRowsBuf.push({ type: 'holiday', date: dateStr, holidayName: holidayNames.get(dateStr) || 'Feiertag' });
|
||||
}
|
||||
});
|
||||
allRowsBuf.sort((a, b) => {
|
||||
const dateA = a.type === 'entry' ? a.entry.date : a.date;
|
||||
const dateB = b.type === 'entry' ? b.entry.date : b.date;
|
||||
return dateA.localeCompare(dateB);
|
||||
});
|
||||
|
||||
// Tabellen-Daten
|
||||
doc.font('Helvetica');
|
||||
let totalHours = 0;
|
||||
let vacationHours = 0;
|
||||
|
||||
entries.forEach((entry) => {
|
||||
allRowsBuf.forEach((row) => {
|
||||
if (row.type === 'holiday') {
|
||||
y = doc.y;
|
||||
x = 50;
|
||||
const rowDataBuf = [formatDate(row.date), '-', '-', '-', fullDayHoursBuf.toFixed(2) + ' h (Feiertag)'];
|
||||
rowDataBuf.forEach((data, i) => {
|
||||
doc.text(data, x, y, { width: colWidths[i], align: 'left' });
|
||||
x += colWidths[i];
|
||||
});
|
||||
doc.moveDown(0.2);
|
||||
doc.fontSize(9).font('Helvetica-Oblique');
|
||||
doc.text('Feiertag: ' + row.holidayName, 60, doc.y, { width: 360 });
|
||||
doc.fontSize(10);
|
||||
doc.moveDown(0.5);
|
||||
y = doc.y;
|
||||
doc.moveTo(50, y).lineTo(430, y).stroke();
|
||||
doc.moveDown(0.3);
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = row.entry;
|
||||
y = doc.y;
|
||||
x = 50;
|
||||
|
||||
const rowData = [
|
||||
formatDate(entry.date),
|
||||
entry.start_time || '-',
|
||||
@@ -427,7 +487,6 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
x += colWidths[i];
|
||||
});
|
||||
|
||||
// Tätigkeiten sammeln
|
||||
const activities = [];
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
const desc = entry[`activity${i}_desc`];
|
||||
@@ -442,13 +501,11 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tätigkeiten anzeigen
|
||||
if (activities.length > 0) {
|
||||
doc.moveDown(0.3);
|
||||
doc.fontSize(9).font('Helvetica-Oblique');
|
||||
doc.text('Tätigkeiten:', 60, doc.y, { width: 380 });
|
||||
doc.moveDown(0.2);
|
||||
|
||||
activities.forEach((activity, idx) => {
|
||||
let activityText = `${idx + 1}. ${activity.desc}`;
|
||||
if (activity.projectNumber) {
|
||||
@@ -462,8 +519,10 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
doc.fontSize(10);
|
||||
}
|
||||
|
||||
// Überstunden und Urlaub anzeigen
|
||||
const overtimeInfo = [];
|
||||
if (holidaySet.has(entry.date)) {
|
||||
overtimeInfo.push('Feiertag: ' + (holidayNames.get(entry.date) || 'Feiertag'));
|
||||
}
|
||||
if (entry.overtime_taken_hours && parseFloat(entry.overtime_taken_hours) > 0) {
|
||||
overtimeInfo.push(`Überstunden genommen: ${parseFloat(entry.overtime_taken_hours).toFixed(2)} h`);
|
||||
}
|
||||
@@ -471,38 +530,30 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
const vacationText = entry.vacation_type === 'full' ? 'Ganzer Tag' : 'Halber Tag';
|
||||
overtimeInfo.push(`Urlaub: ${vacationText}`);
|
||||
}
|
||||
|
||||
if (overtimeInfo.length > 0) {
|
||||
doc.moveDown(0.2);
|
||||
doc.fontSize(9).font('Helvetica-Oblique');
|
||||
overtimeInfo.forEach((info, idx) => {
|
||||
overtimeInfo.forEach((info) => {
|
||||
doc.text(info, 70, doc.y, { width: 360 });
|
||||
doc.moveDown(0.15);
|
||||
});
|
||||
doc.fontSize(10);
|
||||
}
|
||||
|
||||
// Urlaub hat Priorität - wenn Urlaub, zähle nur Urlaubsstunden, nicht zusätzlich Arbeitsstunden
|
||||
const arbeitstage = timesheet.arbeitstage || 5;
|
||||
const fullDayHours = timesheet.wochenstunden > 0 && arbeitstage > 0 ? timesheet.wochenstunden / arbeitstage : 8;
|
||||
if (entry.vacation_type === 'full') {
|
||||
vacationHours += fullDayHours; // Ganzer Tag = (Wochenarbeitszeit / Arbeitstage) Stunden
|
||||
// Bei vollem Tag Urlaub werden keine Arbeitsstunden gezählt
|
||||
vacationHours += fullDayHoursBuf;
|
||||
} else if (entry.vacation_type === 'half') {
|
||||
vacationHours += fullDayHours / 2; // Halber Tag = (Wochenarbeitszeit / Arbeitstage) / 2 Stunden
|
||||
// Bei halbem Tag Urlaub können noch Arbeitsstunden vorhanden sein
|
||||
vacationHours += fullDayHoursBuf / 2;
|
||||
if (entry.total_hours) {
|
||||
totalHours += entry.total_hours;
|
||||
}
|
||||
} else {
|
||||
// Kein Urlaub - zähle nur Arbeitsstunden
|
||||
if (entry.total_hours) {
|
||||
totalHours += entry.total_hours;
|
||||
}
|
||||
}
|
||||
|
||||
doc.moveDown(0.5);
|
||||
|
||||
y = doc.y;
|
||||
doc.moveTo(50, y).lineTo(430, y).stroke();
|
||||
doc.moveDown(0.3);
|
||||
@@ -513,7 +564,6 @@ function generatePDFToBuffer(timesheetId, req) {
|
||||
doc.moveTo(50, y).lineTo(550, y).stroke();
|
||||
doc.moveDown(0.5);
|
||||
doc.font('Helvetica-Bold');
|
||||
// Gesamtstunden = Arbeitsstunden + Urlaubsstunden + Feiertagsstunden
|
||||
const totalHoursWithVacation = totalHours + vacationHours + holidayHours;
|
||||
doc.text(`Gesamtstunden: ${totalHoursWithVacation.toFixed(2)} h`, 50, doc.y);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user