removed and refactored virtual and real worktime

This commit is contained in:
2025-12-12 06:31:03 +01:00
parent f73c2b1a96
commit 1ccc19b85c
12 changed files with 79 additions and 84 deletions

View File

@@ -46,11 +46,11 @@ func fillKurzarbeit(r *http.Request, w http.ResponseWriter) {
if !day.IsKurzArbeit() || !day.IsWorkDay() {
continue
}
if day.GetWorktimeReal(user, models.WorktimeBaseDay) >= day.GetWorktimeVirtual(user, models.WorktimeBaseDay) {
if day.GetWorktime(user, models.WorktimeBaseDay, false) >= day.GetWorktime(user, models.WorktimeBaseDay, true) {
continue
}
worktimeKurzarbeit := day.GetWorktimeVirtual(user, models.WorktimeBaseDay) - day.GetWorktimeReal(user, models.WorktimeBaseDay)
worktimeKurzarbeit := day.GetWorktime(user, models.WorktimeBaseDay, true) - day.GetWorktime(user, models.WorktimeBaseDay, false)
if wDay, ok := day.(*models.WorkDay); !ok || len(wDay.Bookings) == 0 {
continue

View File

@@ -20,7 +20,7 @@ func convertDaysToTypst(days []models.IWorkDay, u models.User) ([]typstDay, erro
var typstDays []typstDay
for _, day := range days {
var thisTypstDay typstDay
work, pause, overtime := day.GetTimesVirtual(u, models.WorktimeBaseWeek)
work, pause, overtime := day.GetTimes(u, models.WorktimeBaseWeek, true)
thisTypstDay.Date = day.Date().Format(DE_DATE)
thisTypstDay.Worktime = helper.FormatDurationFill(work, true)
thisTypstDay.Pausetime = helper.FormatDurationFill(pause, true)
@@ -132,7 +132,7 @@ func createEmployeReport(employee models.User, startDate, endDate time.Time) (by
var actualHours time.Duration
for _, day := range workingDays {
actualHours += day.GetWorktimeVirtual(employee, models.WorktimeBaseDay)
actualHours += day.GetWorktime(employee, models.WorktimeBaseDay, true)
}
worktimeBalance := actualHours - targetHours
@@ -172,8 +172,8 @@ func PDFHandler(w http.ResponseWriter, r *http.Request) {
weeks := models.GetDays(user, startDate, endDate, false)
var aggregatedOvertime, aggregatedWorkTime time.Duration
for _, day := range weeks {
aggregatedOvertime += day.GetOvertimeReal(user, models.WorktimeBaseWeek)
aggregatedWorkTime += day.GetWorktimeVirtual(user, models.WorktimeBaseWeek)
aggregatedOvertime += day.GetOvertime(user, models.WorktimeBaseWeek, false)
aggregatedWorkTime += day.GetWorktime(user, models.WorktimeBaseWeek, true)
}
typstDays, err := convertDaysToTypst(weeks, user)

View File

@@ -84,7 +84,7 @@ func getBookings(w http.ResponseWriter, r *http.Request) {
if day.Date().Before(lastSub) {
continue
}
aggregatedOvertime += day.GetOvertimeReal(user, models.WorktimeBaseDay)
aggregatedOvertime += day.GetOvertime(user, models.WorktimeBaseDay, false)
}
if reportedOvertime, err := user.GetReportedOvertime(); err == nil {
user.Overtime = (reportedOvertime + aggregatedOvertime).Round(time.Minute)

View File

@@ -49,6 +49,43 @@ func (a *Absence) IsMultiDay() bool {
return !a.DateFrom.Equal(a.DateTo)
}
func (a *Absence) GetWorktime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
switch base {
case WorktimeBaseDay:
if a.AbwesenheitTyp.WorkTime <= 0 && includeKurzarbeit {
return u.ArbeitszeitProTagFrac(1)
}
return u.ArbeitszeitProTagFrac(float32(a.AbwesenheitTyp.WorkTime) / 100)
case WorktimeBaseWeek:
if a.AbwesenheitTyp.WorkTime <= 0 && includeKurzarbeit {
return u.ArbeitszeitProTagFrac(0.2)
}
return u.ArbeitszeitProWocheFrac(0.2 * float32(a.AbwesenheitTyp.WorkTime) / 100)
}
return 0
}
func (a *Absence) GetPausetime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
return 0
}
func (a *Absence) GetOvertime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
if a.AbwesenheitTyp.WorkTime > 0 {
return 0
}
switch base {
case WorktimeBaseDay:
return -u.ArbeitszeitProTagFrac(1)
case WorktimeBaseWeek:
return -u.ArbeitszeitProWocheFrac(0.2)
}
return 0
}
func (a *Absence) GetTimes(u User, base WorktimeBase, includeKurzarbeit bool) (work, pause, overtime time.Duration) {
return a.GetWorktime(u, base, includeKurzarbeit), a.GetPausetime(u, base, includeKurzarbeit), a.GetOvertime(u, base, includeKurzarbeit)
}
func (a *Absence) GetWorktimeReal(u User, base WorktimeBase) time.Duration {
if a.AbwesenheitTyp.WorkTime <= 0 {
return 0
@@ -71,9 +108,9 @@ func (a *Absence) GetOvertimeReal(u User, base WorktimeBase) time.Duration {
}
switch base {
case WorktimeBaseDay:
return -u.ArbeitszeitProTag()
return -u.ArbeitszeitProTagFrac(1)
case WorktimeBaseWeek:
return -u.ArbeitszeitProWoche() / 5
return -u.ArbeitszeitProWocheFrac(0.2)
}
return 0
}

View File

@@ -13,14 +13,10 @@ type IWorkDay interface {
IsKurzArbeit() bool
GetDayProgress(User) int8
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)
GetWorktime(User, WorktimeBase, bool) time.Duration
GetPausetime(User, WorktimeBase, bool) time.Duration
GetTimes(User, WorktimeBase, bool) (work, pause, overtime time.Duration)
GetOvertime(User, WorktimeBase, bool) time.Duration
}
func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay {

View File

@@ -31,30 +31,28 @@ const (
)
// Gets the time as is in the db (with corrected pause times)
func (d *WorkDay) GetWorktimeReal(u User, base WorktimeBase) time.Duration {
func (d *WorkDay) GetWorktime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
if includeKurzarbeit && d.IsKurzArbeit() {
return d.kurzArbeitAbsence.GetWorktime(u, base, true)
}
work, pause := calcWorkPause(d.Bookings)
work, pause = correctWorkPause(work, pause)
if (d.worktimeAbsece != Absence{}) {
work += d.worktimeAbsece.GetWorktimeReal(u, WorktimeBaseDay)
work += d.worktimeAbsece.GetWorktimeReal(u, base)
}
return work.Round(time.Minute)
}
// Gets the corrected pause times based on db entries
func (d *WorkDay) GetPausetimeReal(u User, base WorktimeBase) time.Duration {
func (d *WorkDay) GetPausetime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
work, pause := calcWorkPause(d.Bookings)
work, pause = correctWorkPause(work, pause)
return pause.Round(time.Minute)
}
// 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)
if (d.worktimeAbsece != Absence{}) {
work += d.worktimeAbsece.GetWorktimeReal(u, base)
}
func (d *WorkDay) GetOvertime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
work := d.GetWorktime(u, base, includeKurzarbeit)
var targetHours time.Duration
switch base {
case WorktimeBaseDay:
@@ -65,44 +63,8 @@ func (d *WorkDay) GetOvertimeReal(u User, base WorktimeBase) time.Duration {
return (work - targetHours).Round(time.Minute)
}
// 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.ArbeitszeitProWocheFrac(0.2)
default:
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.ArbeitszeitProWocheFrac(0.2)
}
return (work - targetHours).Round(time.Minute)
}
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 (d *WorkDay) GetTimes(u User, base WorktimeBase, includeKurzarbeit bool) (work, pause, overtime time.Duration) {
return d.GetWorktime(u, base, includeKurzarbeit), d.GetPausetime(u, base, includeKurzarbeit), d.GetOvertime(u, base, includeKurzarbeit)
}
func calcWorkPause(bookings []Booking) (work, pause time.Duration) {
@@ -307,7 +269,7 @@ func (d *WorkDay) GetDayProgress(u User) int8 {
if d.RequiresAction() {
return -1
}
workTime := d.GetWorktimeVirtual(u, WorktimeBaseDay)
workTime := d.GetWorktime(u, WorktimeBaseDay, true)
progress := (workTime.Seconds() / u.ArbeitszeitProTag().Seconds()) * 100
return int8(progress)
}

View File

@@ -49,7 +49,7 @@ func TestWorkdayWorktimeDay(t *testing.T) {
t.Run("Calc Absence Worktime: "+tc.testName, func(t *testing.T) {
var testCase = testWorkDay
testCase.Bookings = tc.bookings
workTime := testCase.GetWorktimeReal(testUser, models.WorktimeBaseDay)
workTime := testCase.GetWorktime(testUser, models.WorktimeBaseDay, false)
if workTime != tc.expectedTime {
t.Errorf("GetWorktimeReal not working, time should be %s, but was %s", helper.FormatDurationFill(tc.expectedTime, true), helper.FormatDurationFill(workTime, true))
}
@@ -84,7 +84,7 @@ func TestWorkdayWorktimeWeek(t *testing.T) {
t.Run("Calc Absence Worktime: "+tc.testName, func(t *testing.T) {
var testCase = testWorkDay
testCase.Bookings = tc.bookings
workTime := testCase.GetWorktimeReal(testUser, models.WorktimeBaseWeek)
workTime := testCase.GetWorktime(testUser, models.WorktimeBaseWeek, false)
if workTime != tc.expectedTime {
t.Errorf("GetWorktimeReal not working, time should be %s, but was %s", helper.FormatDurationFill(tc.expectedTime, true), helper.FormatDurationFill(workTime, true))
}
@@ -119,7 +119,7 @@ func TestWorkdayPausetimeDay(t *testing.T) {
t.Run("Calc Absence Worktime: "+tc.testName, func(t *testing.T) {
var testCase = testWorkDay
testCase.Bookings = tc.bookings
workTime := testCase.GetPausetimeReal(testUser, models.WorktimeBaseDay)
workTime := testCase.GetPausetime(testUser, models.WorktimeBaseDay, false)
if workTime != tc.expectedTime {
t.Errorf("GetPausetimeReal not working, time should be %s, but was %s", helper.FormatDurationFill(tc.expectedTime, true), helper.FormatDurationFill(workTime, true))
}
@@ -154,7 +154,7 @@ func TestWorkdayPausetimeWeek(t *testing.T) {
t.Run("Calc Absence Worktime: "+tc.testName, func(t *testing.T) {
var testCase = testWorkDay
testCase.Bookings = tc.bookings
workTime := testCase.GetPausetimeReal(testUser, models.WorktimeBaseWeek)
workTime := testCase.GetPausetime(testUser, models.WorktimeBaseWeek, false)
if workTime != tc.expectedTime {
t.Errorf("GetPausetimeReal not working, time should be %s, but was %s", helper.FormatDurationFill(tc.expectedTime, true), helper.FormatDurationFill(workTime, true))
}

View File

@@ -20,7 +20,7 @@ type WorkWeek struct {
User User
WeekStart time.Time
Worktime time.Duration
WorkTimeVirtual time.Duration
WorktimeVirtual time.Duration
Overtime time.Duration
Status WeekStatus
}
@@ -52,14 +52,14 @@ func (w *WorkWeek) PopulateWithDays(worktime time.Duration, overtime time.Durati
w.Days = GetDays(w.User, w.WeekStart, w.WeekStart.Add(6*24*time.Hour), false)
for _, day := range w.Days {
w.Worktime += day.GetWorktimeReal(w.User, WorktimeBaseDay)
w.WorkTimeVirtual += day.GetWorktimeVirtual(w.User, WorktimeBaseDay)
w.Worktime += day.GetWorktime(w.User, WorktimeBaseDay, false)
w.WorktimeVirtual += day.GetWorktime(w.User, WorktimeBaseDay, true)
}
slog.Debug("Got worktime for user", "worktime", w.Worktime.String(), "virtualWorkTime", w.WorkTimeVirtual.String())
slog.Debug("Got worktime for user", "worktime", w.Worktime.String(), "virtualWorkTime", w.WorktimeVirtual.String())
w.Overtime = w.WorkTimeVirtual - w.User.ArbeitszeitProWoche()
w.Overtime = w.WorktimeVirtual - w.User.ArbeitszeitProWoche()
slog.Debug("Calculated overtime", "worktime", w.Worktime.String(), "virtualWorkTime", w.WorkTimeVirtual.String())
slog.Debug("Calculated overtime", "worktime", w.Worktime.String(), "virtualWorkTime", w.WorktimeVirtual.String())
w.Worktime = w.Worktime.Round(time.Minute)
w.Overtime = w.Overtime.Round(time.Minute)

View File

@@ -36,7 +36,7 @@ templ defaultWeekDayComponent(u models.User, day models.IWorkDay) {
if day.IsWorkDay() {
{{
workDay, _ := day.(*models.WorkDay)
work, pause, _ := workDay.GetTimesReal(u, models.WorktimeBaseDay)
work, pause, _ := workDay.GetTimes(u, models.WorktimeBaseDay, false)
}}
if !workDay.RequiresAction() {
<div class="flex flex-row gap-2">
@@ -81,7 +81,7 @@ templ weekDayComponent(user models.User, day models.WorkDay) {
templ workWeekComponent(week models.WorkWeek, onlyAccept bool) {
{{
year, kw := week.WeekStart.ISOWeek()
progress := (float32(week.WorkTimeVirtual.Hours()) / week.User.ArbeitszeitPerWoche) * 100
progress := (float32(week.WorktimeVirtual.Hours()) / week.User.ArbeitszeitPerWoche) * 100
}}
<div class="employeComponent grid-sub responsive lg:divide-x-1 max-md:divide-y-1 @container">
<div class="grid-cell flex flex-col max-md:bg-neutral-300 gap-2">

View File

@@ -179,7 +179,7 @@ func defaultWeekDayComponent(u models.User, day models.IWorkDay) templ.Component
if day.IsWorkDay() {
workDay, _ := day.(*models.WorkDay)
work, pause, _ := workDay.GetTimesReal(u, models.WorktimeBaseDay)
work, pause, _ := workDay.GetTimes(u, models.WorktimeBaseDay, false)
if !workDay.RequiresAction() {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<div class=\"flex flex-row gap-2\"><span class=\"text-accent\">")
if templ_7745c5c3_Err != nil {
@@ -346,7 +346,7 @@ func workWeekComponent(week models.WorkWeek, onlyAccept bool) templ.Component {
ctx = templ.ClearChildren(ctx)
year, kw := week.WeekStart.ISOWeek()
progress := (float32(week.WorkTimeVirtual.Hours()) / week.User.ArbeitszeitPerWoche) * 100
progress := (float32(week.WorktimeVirtual.Hours()) / week.User.ArbeitszeitPerWoche) * 100
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<div class=\"employeComponent grid-sub responsive lg:divide-x-1 max-md:divide-y-1 @container\"><div class=\"grid-cell flex flex-col max-md:bg-neutral-300 gap-2\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err

View File

@@ -103,8 +103,8 @@ templ defaultDayComponent(day models.IWorkDay) {
if day.IsWorkDay() {
{{
workDay, _ := day.(*models.WorkDay)
work, pause, overtime := workDay.GetTimesVirtual(user, models.WorktimeBaseDay)
work = workDay.GetWorktimeReal(user, models.WorktimeBaseDay)
work, pause, overtime := workDay.GetTimes(user, models.WorktimeBaseDay, true)
work = workDay.GetWorktime(user, models.WorktimeBaseDay, false)
}}
if day.RequiresAction() {
<p class="text-red-600">Bitte anpassen</p>

View File

@@ -297,8 +297,8 @@ func defaultDayComponent(day models.IWorkDay) templ.Component {
if day.IsWorkDay() {
workDay, _ := day.(*models.WorkDay)
work, pause, overtime := workDay.GetTimesVirtual(user, models.WorktimeBaseDay)
work = workDay.GetWorktimeReal(user, models.WorktimeBaseDay)
work, pause, overtime := workDay.GetTimes(user, models.WorktimeBaseDay, true)
work = workDay.GetWorktime(user, models.WorktimeBaseDay, false)
if day.RequiresAction() {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<p class=\"text-red-600\">Bitte anpassen</p>")
if templ_7745c5c3_Err != nil {