refactor attendance calculations to handle multiple entry/exit times and improve time tracking accuracy

This commit is contained in:
2025-10-23 22:11:41 +02:00
parent 5aeac397a1
commit fb63414d69
2 changed files with 53 additions and 23 deletions

View File

@@ -95,21 +95,34 @@ function isValidWorkDay(day) {
return day.dayOfWeek !== 'So' && day.dayOfWeek !== 'Nd' && !day.isPublicHoliday
}
function calculateWorkedTime(entryTime, exitTime) {
if (!entryTime || !exitTime || typeof entryTime !== 'string' || typeof exitTime !== 'string') {
return 0
}
const [eh, em] = entryTime.split(':').map(Number)
const [xh, xm] = exitTime.split(':').map(Number)
if ([eh, em, xh, xm].some((v) => typeof v !== 'number' || isNaN(v))) {
function calculateWorkedTime(entryTimes, exitTimes) {
if (!entryTimes || !exitTimes || !Array.isArray(entryTimes) || !Array.isArray(exitTimes) || entryTimes.length === 0) {
return 0
}
const start = eh * 60 + em
const end = xh * 60 + xm
let totalWorkedMinutes = 0
for (let i = 0; i < entryTimes.length; i++) {
const entryTime = entryTimes[i]
// Use the corresponding exit time, or skip if it doesn't exist
const exitTime = exitTimes[i]
let worked = (end - start) / 60
if (!entryTime || !exitTime || typeof entryTime !== 'string' || typeof exitTime !== 'string') {
continue
}
const [eh, em] = entryTime.split(':').map(Number)
const [xh, xm] = exitTime.split(':').map(Number)
if ([eh, em, xh, xm].some((v) => typeof v !== 'number' || isNaN(v))) {
continue
}
const start = eh * 60 + em
const end = xh * 60 + xm
totalWorkedMinutes += end - start
}
const worked = totalWorkedMinutes / 60
return parseFloat(worked.toFixed(9))
}
@@ -130,23 +143,30 @@ function floatHoursToHHMM(decimalHours) {
}
function calculateDay(day) {
let exitTime = day.exitTime
// Create a mutable copy of exit times to potentially add the current time.
const exitTimes = [...day.exitTime]
if (!day.exitTime || typeof day.exitTime !== 'string' || day.exitTime.trim() === '') {
// const now = new Date().toLocaleString('pl-PL', { timeZone: 'Europe/Warsaw' })
// If there's one more entry than exits, it means the user is currently clocked in.
if (day.entryTime.length > 0 && day.entryTime.length === day.exitTime.length + 1) {
const now = new Date()
const hh = String(now.getHours()).padStart(2, '0')
const mm = String(now.getMinutes()).padStart(2, '0')
const ss = String(now.getSeconds()).padStart(2, '0')
exitTime = `${hh}:${mm}:${ss}`
// Add the current time as the "exit" for the last entry.
exitTimes.push(`${hh}:${mm}:${ss}`)
}
if (!day.entryTime || typeof day.entryTime !== 'string' || day.entryTime.trim() === '') {
if (day.entryTime.length === 0) {
day.workedHours = 0
} else {
day.workedHours = calculateWorkedTime(day.entryTime, exitTime) - 0.25
day.workedHours = parseFloat(day.workedHours.toFixed(9))
day.exitTime = exitTime
// The -0.25 for a 15-minute break seems to be a business rule.
// It should probably only be subtracted once per day, not per interval.
// Let's subtract it from the total.
let totalHours = calculateWorkedTime(day.entryTime, exitTimes)
if (totalHours > 0) {
totalHours -= 0.25
}
day.workedHours = parseFloat(totalHours.toFixed(9))
}
if (isValidWorkDay(day) && !day.isHolidayLeave && !day.isSickLeave) {