From e8f111329392f6eff95a7c9f4b1676ddace8a174 Mon Sep 17 00:00:00 2001 From: tom Date: Thu, 25 Sep 2025 21:52:53 +0200 Subject: [PATCH] using IWorkDay interface for team --- Backend/endpoints/pdf.go | 2 +- Backend/endpoints/time.go | 2 +- Backend/models/absence.go | 7 ++ Backend/models/workDay.go | 13 ++- Backend/models/workWeek.go | 6 +- Backend/templates/pdf.templ | 32 ++++--- Backend/templates/pdf_templ.go | 162 ++++++++++++++++++++------------- 7 files changed, 141 insertions(+), 83 deletions(-) diff --git a/Backend/endpoints/pdf.go b/Backend/endpoints/pdf.go index 50f7130..ce27116 100644 --- a/Backend/endpoints/pdf.go +++ b/Backend/endpoints/pdf.go @@ -29,7 +29,7 @@ func PDFHandler(w http.ResponseWriter, r *http.Request) { //TODO: only accepted weeks - weeks := models.GetWorkDays(user, startDate, endDate) + weeks := models.GetDays(user, startDate, endDate, false) // log.Printf("Using Dates: %s - %s\n", startDate.String(), endDate.String()) templates.PDFReportEmploye(user, weeks, startDate, endDate).Render(r.Context(), w) diff --git a/Backend/endpoints/time.go b/Backend/endpoints/time.go index 9f85c2e..0be3f67 100644 --- a/Backend/endpoints/time.go +++ b/Backend/endpoints/time.go @@ -66,7 +66,7 @@ func getBookings(w http.ResponseWriter, r *http.Request) { } tsTo = tsTo.AddDate(0, 0, 1) // so that today is inside - days := models.GetDays(user, tsFrom, tsTo) + days := models.GetDays(user, tsFrom, tsTo, true) sort.Slice(days, func(i, j int) bool { return days[i].Date().After(days[j].Date()) }) diff --git a/Backend/models/absence.go b/Backend/models/absence.go index a008fde..b0fb959 100644 --- a/Backend/models/absence.go +++ b/Backend/models/absence.go @@ -87,6 +87,13 @@ func (a *Absence) RequiresAction() bool { return false } +func (a *Absence) GetAllWorkTimesVirtual(u User) (work, pause, overtime time.Duration) { + if a.AbwesenheitTyp.WorkTime > 1 { + return u.ArbeitszeitProTag(), 0, 0 + } + return 0, 0, 0 +} + func (a *Absence) Insert() error { qStr, err := DB.Prepare(`INSERT INTO abwesenheit (card_uid, abwesenheit_typ, datum_from, datum_to) VALUES ($1, $2, $3, $4) RETURNING counter_id;`) if err != nil { diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index 0c1f6b9..51025b9 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -4,6 +4,7 @@ import ( "arbeitszeitmessung/helper" "encoding/json" "log" + "sort" "strconv" "time" ) @@ -14,6 +15,7 @@ type IWorkDay interface { TimeWorkReal(User) time.Duration TimePauseReal(User) (work, pause time.Duration) TimeOvertimeReal(User) time.Duration + GetAllWorkTimesVirtual(User) (work, pause, overtime time.Duration) ToString() string IsWorkDay() bool IsKurzArbeit() bool @@ -33,7 +35,7 @@ type WorkDay struct { kurzArbeit bool } -func GetDays(user User, tsFrom, tsTo time.Time) []IWorkDay { +func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay { var allDays map[string]IWorkDay = make(map[string]IWorkDay) var sortedDays []IWorkDay for _, day := range GetWorkDays(user, tsFrom, tsTo) { @@ -60,6 +62,15 @@ func GetDays(user User, tsFrom, tsTo time.Time) []IWorkDay { for _, day := range allDays { sortedDays = append(sortedDays, day) } + if orderedForward { + sort.Slice(sortedDays, func(i, j int) bool { + return sortedDays[i].Date().After(sortedDays[j].Date()) + }) + } else { + sort.Slice(sortedDays, func(i, j int) bool { + return sortedDays[i].Date().Before(sortedDays[j].Date()) + }) + } return sortedDays } diff --git a/Backend/models/workWeek.go b/Backend/models/workWeek.go index aeb7879..7144b8e 100644 --- a/Backend/models/workWeek.go +++ b/Backend/models/workWeek.go @@ -4,7 +4,6 @@ import ( "database/sql" "errors" "log" - "sort" "time" ) @@ -46,10 +45,7 @@ func NewWorkWeek(user User, tsMonday time.Time, populate bool) WorkWeek { } func (w *WorkWeek) PopulateWithDays(worktime time.Duration, overtime time.Duration) { - w.Days = GetDays(w.User, w.WeekStart, w.WeekStart.Add(6*24*time.Hour)) - sort.Slice(w.Days, func(i, j int) bool { - return w.Days[i].Date().Before(w.Days[j].Date()) - }) + w.Days = GetDays(w.User, w.WeekStart, w.WeekStart.Add(6*24*time.Hour), false) for _, day := range w.Days { w.Worktime += day.TimeWorkVirtual(w.User) diff --git a/Backend/templates/pdf.templ b/Backend/templates/pdf.templ index ad6c6b9..2b92d10 100644 --- a/Backend/templates/pdf.templ +++ b/Backend/templates/pdf.templ @@ -6,7 +6,7 @@ import ( "time" ) -templ PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Time, tsEnd time.Time) { +templ PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Time, tsEnd time.Time) { {{ _, kw := tsStart.ISOWeek() noBorder := "" @@ -33,22 +33,32 @@ templ PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Ti noBorder = "border-b-0" } }} -

{ day.Day.Format("02.01.2006") }

+

{ day.Date().Format("02.01.2006") }

- for bookingI := 0; bookingI < len(day.Bookings); bookingI+= 2 { -

{ day.Bookings[bookingI].Timestamp.Format("15:04") }

-

{ day.Bookings[bookingI+1].Timestamp.Format("15:04") }

-

{ day.Bookings[bookingI].BookingType.Name }

+ if day.IsWorkDay() { + {{ + workDay, _ := day.(*models.WorkDay) + }} + for bookingI := 0; bookingI < len(workDay.Bookings); bookingI+= 2 { +

{ workDay.Bookings[bookingI].Timestamp.Format("15:04") }

+

{ workDay.Bookings[bookingI+1].Timestamp.Format("15:04") }

+

{ workDay.Bookings[bookingI].BookingType.Name }

+ } + if workDay.IsKurzArbeit() { +

Kurzarbeit

+ } + } else { + {{ + absentDay, _ := day.(*models.Absence) + }} +

{ absentDay.AbwesenheitTyp.Name }

} - // if (day.Absence != models.Absence{}) { - //

{ day.Absence.AbwesenheitTyp.Name }

- // }
- {{ work, pause, overtime := day.GetAllWorkTimesReal(e) }} + {{ work, pause, overtime := day.GetAllWorkTimesVirtual(e) }} @ColorDuration(work, noBorder) @ColorDuration(pause, noBorder) @ColorDuration(overtime, noBorder+" border-r-0") - if day.Day.Weekday() == time.Friday { + if day.Date().Weekday() == time.Friday {

Wochenende

} } diff --git a/Backend/templates/pdf_templ.go b/Backend/templates/pdf_templ.go index 78d3396..57c5998 100644 --- a/Backend/templates/pdf_templ.go +++ b/Backend/templates/pdf_templ.go @@ -14,7 +14,7 @@ import ( "time" ) -func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Time, tsEnd time.Time) templ.Component { +func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Time, tsEnd time.Time) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -113,9 +113,9 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim return templ_7745c5c3_Err } var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(day.Date().Format("02.01.2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 36, Col: 56} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 36, Col: 59} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -147,61 +147,95 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - for bookingI := 0; bookingI < len(day.Bookings); bookingI += 2 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") + if day.IsWorkDay() { + + workDay, _ := day.(*models.WorkDay) + for bookingI := 0; bookingI < len(workDay.Bookings); bookingI += 2 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(workDay.Bookings[bookingI].Timestamp.Format("15:04")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 43, Col: 64} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(workDay.Bookings[bookingI+1].Timestamp.Format("15:04")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 44, Col: 66} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(workDay.Bookings[bookingI].BookingType.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 45, Col: 55} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(day.Bookings[bookingI].Timestamp.Format("15:04")) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 39, Col: 59} + if workDay.IsKurzArbeit() { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "

Kurzarbeit

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + } else { + + absentDay, _ := day.(*models.Absence) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

") + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(absentDay.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 54, Col: 62} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(day.Bookings[bookingI+1].Timestamp.Format("15:04")) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 40, Col: 61} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var12 string - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(day.Bookings[bookingI].BookingType.Name) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 41, Col: 50} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - work, pause, overtime := day.GetAllWorkTimesReal(e) + work, pause, overtime := day.GetAllWorkTimesVirtual(e) templ_7745c5c3_Err = ColorDuration(work, noBorder).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -209,7 +243,7 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -217,18 +251,18 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - if day.Day.Weekday() == time.Friday { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "

Wochenende

") + if day.Date().Weekday() == time.Friday { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

Wochenende

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -252,9 +286,9 @@ func ColorDuration(d time.Duration, classes string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var13 := templ.GetChildren(ctx) - if templ_7745c5c3_Var13 == nil { - templ_7745c5c3_Var13 = templ.NopComponent + templ_7745c5c3_Var14 := templ.GetChildren(ctx) + if templ_7745c5c3_Var14 == nil { + templ_7745c5c3_Var14 = templ.NopComponent } ctx = templ.ClearChildren(ctx) @@ -262,38 +296,38 @@ func ColorDuration(d time.Duration, classes string) templ.Component { if d.Abs() < time.Minute { color = "text-neutral-300" } - var templ_7745c5c3_Var14 = []any{color + " " + classes} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...) + var templ_7745c5c3_Var15 = []any{color + " " + classes} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var15...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "\">") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var17 string + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDurationFill(d, true)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 76, Col: 72} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }