added worktime base to work time calculations
Some checks failed
Tests / Run Go Tests (push) Failing after 1m4s

This commit is contained in:
2025-10-31 23:57:42 +01:00
parent ac59d2642f
commit 7e5eaebca9
4 changed files with 171 additions and 2 deletions

View File

@@ -20,7 +20,7 @@ func convertDaysToTypst(days []models.IWorkDay, u models.User) ([]typstDay, erro
var typstDays []typstDay var typstDays []typstDay
for _, day := range days { for _, day := range days {
var thisTypstDay typstDay var thisTypstDay typstDay
work, pause, overtime := day.GetAllWorkTimesVirtual(u) work, pause, overtime := day.GetTimesVirtual(u, models.WorktimeBaseWeek)
thisTypstDay.Date = day.Date().Format(DE_DATE) thisTypstDay.Date = day.Date().Format(DE_DATE)
thisTypstDay.Worktime = helper.FormatDurationFill(work, true) thisTypstDay.Worktime = helper.FormatDurationFill(work, true)
thisTypstDay.Pausetime = helper.FormatDurationFill(pause, true) thisTypstDay.Pausetime = helper.FormatDurationFill(pause, true)
@@ -129,6 +129,8 @@ func createEmployeReport(employee models.User, startDate, endDate time.Time) (by
targetHours := (employee.ArbeitszeitProWoche() / 5) * time.Duration(helper.GetWorkingDays(startDate, endDate)) targetHours := (employee.ArbeitszeitProWoche() / 5) * time.Duration(helper.GetWorkingDays(startDate, endDate))
workingDays := models.GetDays(employee, startDate, endDate, false) workingDays := models.GetDays(employee, startDate, endDate, false)
slog.Debug("Baseline Working hours", "targetHours", targetHours.Hours())
var actualHours time.Duration var actualHours time.Duration
for _, day := range workingDays { for _, day := range workingDays {
actualHours += day.TimeWorkVirtual(employee) actualHours += day.TimeWorkVirtual(employee)

View File

@@ -31,6 +31,7 @@ func FormatDuration(d time.Duration) string {
// Converts duration to string // Converts duration to string
func FormatDurationFill(d time.Duration, fill bool) string { func FormatDurationFill(d time.Duration, fill bool) string {
return fmt.Sprintf("%.1f", d.Hours())
hours := int(d.Abs().Hours()) hours := int(d.Abs().Hours())
minutes := int(d.Abs().Minutes()) % 60 minutes := int(d.Abs().Minutes()) % 60
sign := "" sign := ""

View File

@@ -49,6 +49,55 @@ func (a *Absence) IsMultiDay() bool {
return !a.DateFrom.Equal(a.DateTo) return !a.DateFrom.Equal(a.DateTo)
} }
func (a *Absence) GetWorktimeReal(u User, base WorktimeBase) time.Duration {
if a.AbwesenheitTyp.WorkTime <= 1 {
return 0
}
switch base {
case WorktimeBaseDay:
return u.ArbeitszeitProTag()
case WorktimeBaseWeek:
return u.ArbeitszeitProWoche() / 5
}
return 0
}
func (a *Absence) GetPausetimeReal(u User, base WorktimeBase) time.Duration {
return 0
}
func (a *Absence) GetOvertimeReal(u User, base WorktimeBase) time.Duration {
if a.AbwesenheitTyp.WorkTime > 1 {
return 0
}
switch base {
case WorktimeBaseDay:
return -u.ArbeitszeitProTag()
case WorktimeBaseWeek:
return -u.ArbeitszeitProWoche() / 5
}
return 0
}
func (a *Absence) GetWorktimeVirtual(u User, base WorktimeBase) time.Duration {
return a.GetWorktimeReal(u, base)
}
func (a *Absence) GetPausetimeVirtual(u User, base WorktimeBase) time.Duration {
return a.GetPausetimeReal(u, base)
}
func (a *Absence) GetOvertimeVirtual(u User, base WorktimeBase) time.Duration {
return a.GetOvertimeReal(u, base)
}
func (a *Absence) GetTimesReal(u User, base WorktimeBase) (work, pause, overtime time.Duration) {
return a.GetWorktimeReal(u, base), a.GetPausetimeReal(u, base), a.GetOvertimeReal(u, base)
}
func (a *Absence) GetTimesVirtual(u User, base WorktimeBase) (work, pause, overtime time.Duration) {
return a.GetWorktimeVirtual(u, base), a.GetPausetimeVirtual(u, base), a.GetOvertimeVirtual(u, base)
}
func (a *Absence) TimeWorkVirtual(u User) time.Duration { func (a *Absence) TimeWorkVirtual(u User) time.Duration {
return a.TimeWorkReal(u) return a.TimeWorkReal(u)
} }

View File

@@ -22,6 +22,14 @@ type IWorkDay interface {
IsKurzArbeit() bool IsKurzArbeit() bool
GetDayProgress(User) int8 GetDayProgress(User) int8
RequiresAction() bool RequiresAction() bool
GetWorktimeReal(User, WorktimeBase) time.Duration
GetPausetimeReal(User, WorktimeBase) time.Duration
GetOvertimeReal(User, WorktimeBase) time.Duration
GetWorktimeVirtual(User, WorktimeBase) time.Duration
GetPausetimeVirtual(User, WorktimeBase) time.Duration
GetOvertimeVirtual(User, WorktimeBase) time.Duration
GetTimesReal(User, WorktimeBase) (work, pause, overtime time.Duration)
GetTimesVirtual(User, WorktimeBase) (work, pause, overtime time.Duration)
} }
type WorkDay struct { type WorkDay struct {
@@ -37,6 +45,13 @@ type WorkDay struct {
kurzArbeitAbsence Absence kurzArbeitAbsence Absence
} }
type WorktimeBase string
const (
WorktimeBaseWeek WorktimeBase = "week"
WorktimeBaseDay WorktimeBase = "day"
)
func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay { func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay {
var allDays map[string]IWorkDay = make(map[string]IWorkDay) var allDays map[string]IWorkDay = make(map[string]IWorkDay)
@@ -66,6 +81,108 @@ func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay
return sortedDays return sortedDays
} }
// Gets the time as is in the db (with corrected pause times)
func (d *WorkDay) GetWorktimeReal(u User, base WorktimeBase) time.Duration {
work, pause := calcWorkPause(d.Bookings)
work, pause = correctWorkPause(work, pause)
return work
}
// Gets the corrected pause times based on db entries
func (d *WorkDay) GetPausetimeReal(u User, base WorktimeBase) time.Duration {
work, pause := calcWorkPause(d.Bookings)
work, pause = correctWorkPause(work, pause)
return pause
}
// Returns the overtime based on the db entries
func (d *WorkDay) GetOvertimeReal(u User, base WorktimeBase) time.Duration {
work, pause := calcWorkPause(d.Bookings)
work, pause = correctWorkPause(work, pause)
var targetHours time.Duration
switch base {
case WorktimeBaseDay:
targetHours = u.ArbeitszeitProTag()
case WorktimeBaseWeek:
targetHours = u.ArbeitszeitProWoche() / 5
}
return work - targetHours
}
// Returns the worktime based on absence or kurzarbeit
func (d *WorkDay) GetWorktimeVirtual(u User, base WorktimeBase) time.Duration {
if !d.IsKurzArbeit() {
return d.GetWorktimeReal(u, base)
}
switch base {
case WorktimeBaseDay:
return u.ArbeitszeitProTag()
case WorktimeBaseWeek:
return u.ArbeitszeitProWoche() / 5
}
return 0
}
func (d *WorkDay) GetPausetimeVirtual(u User, base WorktimeBase) time.Duration {
return d.GetPausetimeReal(u, base)
}
func (d *WorkDay) GetOvertimeVirtual(u User, base WorktimeBase) time.Duration {
work := d.GetWorktimeVirtual(u, base)
var targetHours time.Duration
switch base {
case WorktimeBaseDay:
targetHours = u.ArbeitszeitProTag()
case WorktimeBaseWeek:
targetHours = u.ArbeitszeitProWoche() / 5
}
return work - targetHours
}
func (d *WorkDay) GetTimesReal(u User, base WorktimeBase) (work, pause, overtime time.Duration) {
return d.GetWorktimeReal(u, base), d.GetPausetimeReal(u, base), d.GetOvertimeReal(u, base)
}
func (d *WorkDay) GetTimesVirtual(u User, base WorktimeBase) (work, pause, overtime time.Duration) {
return d.GetWorktimeVirtual(u, base), d.GetPausetimeVirtual(u, base), d.GetOvertimeVirtual(u, base)
}
func calcWorkPause(bookings []Booking) (work, pause time.Duration) {
var lastBooking Booking
for _, b := range bookings {
if b.CheckInOut%2 == 1 {
if !lastBooking.Timestamp.IsZero() {
pause += b.Timestamp.Sub(lastBooking.Timestamp)
}
} else {
work += b.Timestamp.Sub(lastBooking.Timestamp)
}
lastBooking = b
}
if len(bookings)%2 == 1 {
work += time.Since(lastBooking.Timestamp.Local())
}
return work, pause
}
func correctWorkPause(workIn, pauseIn time.Duration) (work, pause time.Duration) {
if workIn <= 6*time.Hour || pauseIn > 45*time.Minute {
return workIn, pauseIn
}
var diff time.Duration
if workIn <= (9*time.Hour) && pauseIn < 30*time.Minute {
diff = 30*time.Minute - pauseIn
} else if pauseIn < 45*time.Minute {
diff = 45*time.Minute - pauseIn
}
work = workIn - diff
pause = pauseIn + diff
return work, pause
}
func sortDays(days map[string]IWorkDay, forward bool) []IWorkDay { func sortDays(days map[string]IWorkDay, forward bool) []IWorkDay {
var sortedDays []IWorkDay var sortedDays []IWorkDay
for _, day := range days { for _, day := range days {
@@ -127,7 +244,7 @@ func (d *WorkDay) TimeWorkReal(u User) time.Duration {
if helper.IsSameDate(d.Date(), time.Now()) && len(d.Bookings)%2 == 1 { if helper.IsSameDate(d.Date(), time.Now()) && len(d.Bookings)%2 == 1 {
d.realWorkTime += time.Since(lastBooking.Timestamp.Local()) d.realWorkTime += time.Since(lastBooking.Timestamp.Local())
} }
slog.Debug("Calculated RealWorkTime for user", "user", u, slog.String("worktime", d.realWorkTime.String())) // slog.Debug("Calculated RealWorkTime for user", "user", u, slog.String("worktime", d.realWorkTime.String()))
return d.realWorkTime return d.realWorkTime
} }