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