From 834df97c650b5b85d84d9829deda67b2c3232a37 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Mon, 20 Oct 2025 09:41:50 +0200 Subject: [PATCH] Refactor TimeEntryService to enhance time calculations by incorporating missing break minutes into remaining time calculations. Update pause duration handling to account for timefix corrections, ensuring accurate representation of start and end times. Improve server value usage logic in StatusBox component for better handling of worked time display. --- backend/src/services/TimeEntryService.js | 64 +++++++++++++++++++++--- frontend/src/components/StatusBox.vue | 8 +-- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/backend/src/services/TimeEntryService.js b/backend/src/services/TimeEntryService.js index 52bca27..c3b5ed9 100644 --- a/backend/src/services/TimeEntryService.js +++ b/backend/src/services/TimeEntryService.js @@ -699,9 +699,9 @@ class TimeEntryService { const currentTime = new Date(); // ===== GENERELL ===== - // Verbleibende Zeit = Offen - Gesamt-Überstunden + // Verbleibende Zeit = Offen - Gesamt-Überstunden + fehlende Pausen const generalOvertimeMinutes = totalOvertimeResult.minutes || 0; - const generalRemainingMinutes = openMinutes - generalOvertimeMinutes; + const generalRemainingMinutes = openMinutes - generalOvertimeMinutes + missingBreakMinutes; if (generalRemainingMinutes <= 0) { adjustedEndTodayGeneral = 'Arbeitsende erreicht'; @@ -714,9 +714,9 @@ class TimeEntryService { } // ===== WOCHE ===== - // Verbleibende Zeit = Offen - Wochen-Über/Unterstunden + // Verbleibende Zeit = Offen - Wochen-Über/Unterstunden + fehlende Pausen const weekOvertimeMinutes = overtimeMinutes; // Bereits berechnet - const weekRemainingMinutes = openMinutes - weekOvertimeMinutes; + const weekRemainingMinutes = openMinutes - weekOvertimeMinutes + missingBreakMinutes; if (weekRemainingMinutes <= 0) { adjustedEndTodayWeek = 'Arbeitsende erreicht'; @@ -2220,8 +2220,13 @@ class TimeEntryService { return eDate >= startDate; }); + const pauseStarts = {}; + // Hole Timefixes für alle relevanten Einträge (inklusive Pausen) + const allEntryIds = relevantEntries.map(e => e.id); + const pauseTimefixMap = await worklogRepository.getTimefixesByWorklogIds(allEntryIds); + relevantEntries.forEach(entry => { let eState = entry.state; if (typeof eState === 'string') { @@ -2239,7 +2244,15 @@ class TimeEntryService { } else if (eAction === 'stop pause' && entry.relatedTo_id) { const startPause = pauseStarts[entry.relatedTo_id]; if (startPause) { - const duration = new Date(entry.tstamp).getTime() - new Date(startPause.tstamp).getTime(); + // Prüfe auf Timefix-Korrekturen für Pausen + const pauseStartFix = pauseTimefixMap.get(startPause.id)?.find(f => f.fix_type === 'start pause'); + const pauseEndFix = pauseTimefixMap.get(entry.id)?.find(f => f.fix_type === 'stop pause'); + + // Verwende korrigierte Zeiten falls vorhanden + const pStartTime = pauseStartFix?.fix_date_time || startPause.tstamp; + const pEndTime = pauseEndFix?.fix_date_time || entry.tstamp; + + const duration = new Date(pEndTime).getTime() - new Date(pStartTime).getTime(); pauseDurations.push(duration); delete pauseStarts[entry.relatedTo_id]; } @@ -2250,12 +2263,47 @@ class TimeEntryService { const runningPauseIds = Object.keys(pauseStarts); if (runningPauseIds.length > 0) { const pauseId = parseInt(runningPauseIds[0]); - currentPauseStart = pauseStarts[pauseId].tstamp; + const pauseEntry = pauseStarts[pauseId]; + + // Prüfe auf Timefix-Korrektur für laufende Pause + const currentPauseTimefix = pauseTimefixMap.get(pauseId)?.find(f => f.fix_type === 'start pause'); + currentPauseStart = currentPauseTimefix?.fix_date_time || pauseEntry.tstamp; } + // Prüfe auf Timefix-Korrektur für die Start-Zeit (timefixMap bereits geholt in pauseTimefixMap) + const startTimefix = pauseTimefixMap.get(startWorkId)?.find(f => f.fix_type === 'start work'); + + let displayStartTime = startWorkEntry.tstamp; + if (startTimefix && startTimefix.fix_date_time) { + // Verwende korrigierte Zeit + displayStartTime = startTimefix.fix_date_time; + } + + // Stelle sicher, dass startTime ein String ist (kein Date-Objekt) + // Konvertiere UTC zu lokaler Zeit für Frontend + let startTimeStr; + if (typeof displayStartTime === 'string') { + // Wenn es ein UTC-String ist, konvertiere zu lokaler Zeit + const utcDate = new Date(displayStartTime); + const year = utcDate.getFullYear(); + const month = String(utcDate.getMonth() + 1).padStart(2, '0'); + const day = String(utcDate.getDate()).padStart(2, '0'); + const hours = String(utcDate.getHours()).padStart(2, '0'); + const minutes = String(utcDate.getMinutes()).padStart(2, '0'); + const seconds = String(utcDate.getSeconds()).padStart(2, '0'); + startTimeStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; + } else { + startTimeStr = displayStartTime.toISOString(); + } + + // Stelle sicher, dass currentPauseStart auch ein String ist + const currentPauseStartStr = currentPauseStart + ? (typeof currentPauseStart === 'string' ? currentPauseStart : currentPauseStart.toISOString()) + : null; + const result = { id: startWorkId, - startTime: startWorkEntry.tstamp, + startTime: startTimeStr, // Explizit als String endTime: null, description: (state?.description || ''), project: (state?.project || 'Allgemein'), @@ -2263,7 +2311,7 @@ class TimeEntryService { isRunning: true, userId: uid, pauses: pauseDurations, - currentPauseStart: currentPauseStart + currentPauseStart: currentPauseStartStr }; return result; diff --git a/frontend/src/components/StatusBox.vue b/frontend/src/components/StatusBox.vue index 7c75408..359dc22 100644 --- a/frontend/src/components/StatusBox.vue +++ b/frontend/src/components/StatusBox.vue @@ -157,8 +157,10 @@ const updateCurrentlyWorkedTime = () => { return } - // Wenn wir einen Server-Wert haben, nutze diesen als Basis - if (serverWorkedTime.value && serverTimestamp.value) { + // Verwende Server-Werte nur, wenn NICHT gearbeitet wird (oder kein laufender Start vorhanden) + const shouldUseServerSummary = !workStartTime.value + + if (shouldUseServerSummary && serverWorkedTime.value && serverTimestamp.value) { // Parse Server-Zeit (HH:MM:SS) const parts = serverWorkedTime.value.split(':') const serverSeconds = parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]) @@ -181,7 +183,7 @@ const updateCurrentlyWorkedTime = () => { currentlyWorkedTime.value = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` } else { - // Fallback: Wenn kein Server-Wert, aber workStartTime vorhanden + // Fallback/Standard: Aus Startzeit berechnen (bevorzugt bei laufender Arbeit) if (!workStartTime.value) { currentlyWorkedTime.value = '—' return