Umstellung auf Arbeitstage
This commit is contained in:
@@ -12,7 +12,7 @@ function registerVerwaltungRoutes(app) {
|
||||
// Verwaltungs-Bereich
|
||||
app.get('/verwaltung', requireVerwaltung, (req, res) => {
|
||||
db.all(`
|
||||
SELECT wt.*, u.firstname, u.lastname, u.username, u.personalnummer, u.wochenstunden, u.urlaubstage, u.overtime_offset_hours, u.vacation_offset_days,
|
||||
SELECT wt.*, u.firstname, u.lastname, u.username, u.personalnummer, u.wochenstunden, u.urlaubstage, u.overtime_offset_hours, u.vacation_offset_days, u.arbeitstage,
|
||||
dl.firstname as downloaded_by_firstname,
|
||||
dl.lastname as downloaded_by_lastname,
|
||||
(SELECT COUNT(*) FROM weekly_timesheets wt2
|
||||
@@ -217,115 +217,191 @@ function registerVerwaltungRoutes(app) {
|
||||
}
|
||||
|
||||
// User-Daten abrufen
|
||||
db.get('SELECT wochenstunden, urlaubstage, overtime_offset_hours, vacation_offset_days FROM users WHERE id = ?', [userId], (err, user) => {
|
||||
db.get('SELECT wochenstunden, urlaubstage, overtime_offset_hours, vacation_offset_days, arbeitstage FROM users WHERE id = ?', [userId], (err, user) => {
|
||||
if (err || !user) {
|
||||
return res.status(500).json({ error: 'Fehler beim Abrufen der User-Daten' });
|
||||
}
|
||||
|
||||
const wochenstunden = user.wochenstunden || 0;
|
||||
const arbeitstage = user.arbeitstage || 5;
|
||||
const fullDayHours = wochenstunden > 0 && arbeitstage > 0 ? wochenstunden / arbeitstage : 8;
|
||||
const urlaubstage = user.urlaubstage || 0;
|
||||
const overtimeOffsetHours = user.overtime_offset_hours ? parseFloat(user.overtime_offset_hours) : 0;
|
||||
const vacationOffsetDays = user.vacation_offset_days ? parseFloat(user.vacation_offset_days) : 0;
|
||||
|
||||
// Einträge für die Woche abrufen
|
||||
db.all(`SELECT date, total_hours, overtime_taken_hours, vacation_type, sick_status
|
||||
FROM timesheet_entries
|
||||
WHERE user_id = ? AND date >= ? AND date <= ?
|
||||
ORDER BY date`,
|
||||
[userId, week_start, week_end],
|
||||
(err, entries) => {
|
||||
// Alle bereits genommenen Urlaubstage aus eingereichten Wochen berechnen
|
||||
// Zuerst: Alle eingereichten Wochen abrufen
|
||||
db.all(`SELECT DISTINCT week_start, week_end
|
||||
FROM weekly_timesheets
|
||||
WHERE user_id = ? AND status = 'eingereicht'
|
||||
ORDER BY week_start`,
|
||||
[userId],
|
||||
(err, weeks) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: 'Fehler beim Abrufen der Einträge' });
|
||||
return res.status(500).json({ error: 'Fehler beim Abrufen der Wochen' });
|
||||
}
|
||||
|
||||
// Berechnungen
|
||||
let totalHours = 0;
|
||||
let overtimeTaken = 0;
|
||||
let vacationDays = 0;
|
||||
let vacationHours = 0;
|
||||
let sickDays = 0;
|
||||
// Für jede Woche die neuesten Einträge abrufen
|
||||
let processedWeeks = 0;
|
||||
let totalVacationDays = 0;
|
||||
const vacationByDate = {};
|
||||
|
||||
entries.forEach(entry => {
|
||||
if (entry.overtime_taken_hours) {
|
||||
overtimeTaken += entry.overtime_taken_hours;
|
||||
}
|
||||
|
||||
// Krankheitstage zählen
|
||||
if (entry.sick_status === 1 || entry.sick_status === true) {
|
||||
sickDays += 1;
|
||||
}
|
||||
|
||||
// Urlaub hat Priorität - wenn Urlaub, zähle nur Urlaubsstunden, nicht zusätzlich Arbeitsstunden
|
||||
if (entry.vacation_type === 'full') {
|
||||
vacationDays += 1;
|
||||
vacationHours += 8; // Ganzer Tag = 8 Stunden
|
||||
// Bei vollem Tag Urlaub werden keine Arbeitsstunden gezählt
|
||||
} else if (entry.vacation_type === 'half') {
|
||||
vacationDays += 0.5;
|
||||
vacationHours += 4; // Halber Tag = 4 Stunden
|
||||
// Bei halbem Tag Urlaub können noch Arbeitsstunden vorhanden sein
|
||||
// WICHTIG: total_hours enthält bereits Wochenend-Prozentsätze (aus timesheet.js)
|
||||
if (entry.total_hours) {
|
||||
totalHours += parseFloat(entry.total_hours) || 0;
|
||||
}
|
||||
} else {
|
||||
// Kein Urlaub - zähle nur Arbeitsstunden
|
||||
// WICHTIG: total_hours enthält bereits Wochenend-Prozentsätze (aus timesheet.js)
|
||||
if (entry.total_hours) {
|
||||
totalHours += parseFloat(entry.total_hours) || 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Feiertage für die Woche laden (8h pro Feiertag; Arbeit an Feiertag = Überstunden)
|
||||
getHolidaysForDateRange(week_start, week_end)
|
||||
.catch(() => new Set())
|
||||
.then((holidaySet) => {
|
||||
// Anzahl Werktage berechnen (Montag-Freitag)
|
||||
const startDate = new Date(week_start);
|
||||
const endDate = new Date(week_end);
|
||||
let workdays = 0;
|
||||
let holidayHours = 0;
|
||||
for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
|
||||
const day = d.getDay();
|
||||
if (day >= 1 && day <= 5) { // Montag bis Freitag
|
||||
workdays++;
|
||||
const dateStr = d.toISOString().split('T')[0];
|
||||
if (holidaySet.has(dateStr)) holidayHours += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Sollstunden berechnen
|
||||
const sollStunden = (wochenstunden / 5) * workdays;
|
||||
|
||||
// Überstunden: (Tatsächliche Stunden + Urlaubsstunden + Feiertagsstunden) - Sollstunden
|
||||
const totalHoursWithVacation = totalHours + vacationHours + holidayHours;
|
||||
const overtimeHours = totalHoursWithVacation - sollStunden;
|
||||
const remainingOvertime = overtimeHours - overtimeTaken;
|
||||
const remainingOvertimeWithOffset = remainingOvertime + overtimeOffsetHours;
|
||||
|
||||
// Verbleibende Urlaubstage
|
||||
const remainingVacation = urlaubstage - vacationDays + vacationOffsetDays;
|
||||
|
||||
res.json({
|
||||
wochenstunden,
|
||||
urlaubstage,
|
||||
totalHours,
|
||||
sollStunden,
|
||||
overtimeHours,
|
||||
overtimeTaken,
|
||||
remainingOvertime,
|
||||
overtimeOffsetHours,
|
||||
remainingOvertimeWithOffset,
|
||||
vacationDays,
|
||||
vacationOffsetDays,
|
||||
remainingVacation,
|
||||
sickDays,
|
||||
workdays
|
||||
});
|
||||
if (!weeks || weeks.length === 0) {
|
||||
// Keine eingereichten Wochen - setze totalVacationDays auf 0
|
||||
totalVacationDays = 0;
|
||||
// Weiter mit der normalen Verarbeitung der aktuellen Woche
|
||||
processCurrentWeek(0);
|
||||
} else {
|
||||
weeks.forEach((week) => {
|
||||
// Einträge für diese Woche abrufen (nur neueste pro Tag)
|
||||
db.all(`SELECT date, vacation_type, updated_at, id
|
||||
FROM timesheet_entries
|
||||
WHERE user_id = ? AND date >= ? AND date <= ?
|
||||
AND vacation_type IS NOT NULL
|
||||
AND vacation_type != ''
|
||||
ORDER BY date, updated_at DESC, id DESC`,
|
||||
[userId, week.week_start, week.week_end],
|
||||
(err, weekEntries) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: 'Fehler beim Abrufen der Einträge' });
|
||||
}
|
||||
|
||||
// Filtere auf neuesten Eintrag pro Tag
|
||||
(weekEntries || []).forEach(entry => {
|
||||
const existing = vacationByDate[entry.date];
|
||||
if (!existing) {
|
||||
vacationByDate[entry.date] = entry;
|
||||
} else {
|
||||
// Vergleiche updated_at (falls vorhanden) oder id (höhere ID = neuer)
|
||||
const existingTime = existing.updated_at ? new Date(existing.updated_at).getTime() : 0;
|
||||
const currentTime = entry.updated_at ? new Date(entry.updated_at).getTime() : 0;
|
||||
if (currentTime > existingTime || (currentTime === existingTime && entry.id > existing.id)) {
|
||||
vacationByDate[entry.date] = entry;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
processedWeeks++;
|
||||
if (processedWeeks === weeks.length) {
|
||||
// Alle Wochen verarbeitet - summiere Urlaubstage
|
||||
Object.values(vacationByDate).forEach(entry => {
|
||||
if (entry.vacation_type === 'full') {
|
||||
totalVacationDays += 1;
|
||||
} else if (entry.vacation_type === 'half') {
|
||||
totalVacationDays += 0.5;
|
||||
}
|
||||
});
|
||||
|
||||
// Weiter mit der normalen Verarbeitung der aktuellen Woche
|
||||
processCurrentWeek(totalVacationDays);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function processCurrentWeek(totalVacationDays) {
|
||||
// Einträge für die Woche abrufen
|
||||
db.all(`SELECT date, total_hours, overtime_taken_hours, vacation_type, sick_status
|
||||
FROM timesheet_entries
|
||||
WHERE user_id = ? AND date >= ? AND date <= ?
|
||||
ORDER BY date`,
|
||||
[userId, week_start, week_end],
|
||||
(err, entries) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: 'Fehler beim Abrufen der Einträge' });
|
||||
}
|
||||
|
||||
// Berechnungen
|
||||
let totalHours = 0;
|
||||
let overtimeTaken = 0;
|
||||
let vacationDays = 0;
|
||||
let vacationHours = 0;
|
||||
let sickDays = 0;
|
||||
|
||||
entries.forEach(entry => {
|
||||
if (entry.overtime_taken_hours) {
|
||||
overtimeTaken += entry.overtime_taken_hours;
|
||||
}
|
||||
|
||||
// Krankheitstage zählen
|
||||
if (entry.sick_status === 1 || entry.sick_status === true) {
|
||||
sickDays += 1;
|
||||
}
|
||||
|
||||
// Urlaub hat Priorität - wenn Urlaub, zähle nur Urlaubsstunden, nicht zusätzlich Arbeitsstunden
|
||||
if (entry.vacation_type === 'full') {
|
||||
vacationDays += 1;
|
||||
vacationHours += fullDayHours; // Ganzer Tag = (Wochenarbeitszeit / Arbeitstage) Stunden
|
||||
// Bei vollem Tag Urlaub werden keine Arbeitsstunden gezählt
|
||||
} else if (entry.vacation_type === 'half') {
|
||||
vacationDays += 0.5;
|
||||
vacationHours += fullDayHours / 2; // Halber Tag = (Wochenarbeitszeit / Arbeitstage) / 2 Stunden
|
||||
// Bei halbem Tag Urlaub können noch Arbeitsstunden vorhanden sein
|
||||
// WICHTIG: total_hours enthält bereits Wochenend-Prozentsätze (aus timesheet.js)
|
||||
if (entry.total_hours) {
|
||||
totalHours += parseFloat(entry.total_hours) || 0;
|
||||
}
|
||||
} else {
|
||||
// Kein Urlaub - zähle nur Arbeitsstunden
|
||||
// WICHTIG: total_hours enthält bereits Wochenend-Prozentsätze (aus timesheet.js)
|
||||
if (entry.total_hours) {
|
||||
totalHours += parseFloat(entry.total_hours) || 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Feiertage für die Woche laden ((Wochenarbeitszeit / Arbeitstage) pro Feiertag; Arbeit an Feiertag = Überstunden)
|
||||
getHolidaysForDateRange(week_start, week_end)
|
||||
.catch(() => new Set())
|
||||
.then((holidaySet) => {
|
||||
// Anzahl Werktage berechnen (Montag-Freitag)
|
||||
const startDate = new Date(week_start);
|
||||
const endDate = new Date(week_end);
|
||||
let workdays = 0;
|
||||
let holidayHours = 0;
|
||||
for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
|
||||
const day = d.getDay();
|
||||
if (day >= 1 && day <= 5) { // Montag bis Freitag
|
||||
workdays++;
|
||||
const dateStr = d.toISOString().split('T')[0];
|
||||
if (holidaySet.has(dateStr)) holidayHours += fullDayHours;
|
||||
}
|
||||
}
|
||||
|
||||
// Sollstunden berechnen
|
||||
const sollStunden = (wochenstunden / arbeitstage) * workdays;
|
||||
|
||||
// Überstunden: (Tatsächliche Stunden + Urlaubsstunden + Feiertagsstunden) - Sollstunden
|
||||
const totalHoursWithVacation = totalHours + vacationHours + holidayHours;
|
||||
const overtimeHours = totalHoursWithVacation - sollStunden;
|
||||
const remainingOvertime = overtimeHours - overtimeTaken;
|
||||
const remainingOvertimeWithOffset = remainingOvertime + overtimeOffsetHours;
|
||||
|
||||
// Verbleibende Urlaubstage (berücksichtigt alle eingereichten Wochen, nicht nur die aktuelle)
|
||||
const remainingVacation = urlaubstage - totalVacationDays + vacationOffsetDays;
|
||||
|
||||
res.json({
|
||||
wochenstunden,
|
||||
urlaubstage,
|
||||
totalHours,
|
||||
sollStunden,
|
||||
overtimeHours,
|
||||
overtimeTaken,
|
||||
remainingOvertime,
|
||||
overtimeOffsetHours,
|
||||
remainingOvertimeWithOffset,
|
||||
vacationDays,
|
||||
vacationOffsetDays,
|
||||
remainingVacation,
|
||||
totalVacationDays,
|
||||
sickDays,
|
||||
workdays
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user