From ccded6d76bd0b0412775ed841e4846cbb2a62666 Mon Sep 17 00:00:00 2001 From: tom Date: Sat, 13 Sep 2025 14:11:26 +0200 Subject: [PATCH 1/3] reworked time Calculations --- Backend/models/booking_test.go | 47 +++++++++++++++++++ Backend/models/workDay.go | 86 +++++++++++++++++++--------------- Backend/models/workDay_test.go | 82 ++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 37 deletions(-) create mode 100644 Backend/models/booking_test.go create mode 100644 Backend/models/workDay_test.go diff --git a/Backend/models/booking_test.go b/Backend/models/booking_test.go new file mode 100644 index 0000000..032c59e --- /dev/null +++ b/Backend/models/booking_test.go @@ -0,0 +1,47 @@ +package models_test + +import ( + "arbeitszeitmessung/models" + "time" +) + +var testBookingType = models.BookingType{ + Id: 1, + Name: "Büro", +} + +var testBookings8hrs = []models.Booking{models.Booking{ + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 08:00")), + BookingType: testBookingType, +}, models.Booking{ + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 16:00")), + BookingType: testBookingType, +}} + +var testBookings6hrs = []models.Booking{models.Booking{ + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 08:00")), + BookingType: testBookingType, +}, models.Booking{ + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 14:00")), + BookingType: testBookingType, +}} + +var testBookings10hrs = []models.Booking{models.Booking{ + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 08:00")), + BookingType: testBookingType, +}, models.Booking{ + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 18:00")), + BookingType: testBookingType, +}} diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index cf8df46..fda0704 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -19,7 +19,7 @@ type WorkDay struct { Absence Absence } -func GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay { +func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay { var workDays []WorkDay var workSec, pauseSec float64 @@ -97,7 +97,7 @@ ORDER BY d.work_date ASC;`) } defer qStr.Close() - rows, err := qStr.Query(card_uid, tsFrom, tsTo) + rows, err := qStr.Query(user.CardUID, tsFrom, tsTo) if err != nil { log.Println("Error getting rows!") return workDays @@ -125,21 +125,20 @@ ORDER BY d.work_date ASC;`) } if absenceType.Valid { - workDay.Absence, err = NewAbsence(card_uid, int(absenceType.Int16), workDay.Day) - // log.Println("Found absence", workDay.Absence) + workDay.Absence, err = NewAbsence(user.CardUID, int(absenceType.Int16), workDay.Day) + workDay.CalcRealWorkTime(user) } if workDay.Day.Equal(time.Now().Truncate(24 * time.Hour)) { - workDay.getWorkTime() + workDay.CalcRealWorkTime(user) + workDay.CalcWorkPauseDiff(user) } else { - workDay.calcPauseTime() + workDay.CalcWorkPauseDiff(user) } if emptyDays && workDay.Day.Weekday() >= 1 && workDay.Day.Weekday() <= 5 { workDays = append(workDays, workDay) } else if len(workDay.Bookings) > 0 || (workDay.Absence != Absence{}) { workDays = append(workDays, workDay) - // } else { - // log.Println("no booking on day", workDay.Day.Format("02.01.2006")) } } if err = rows.Err(); err != nil { @@ -148,45 +147,56 @@ ORDER BY d.work_date ASC;`) return workDays } -func (d *WorkDay) calcPauseTime() { - if d.workTime > 6*time.Hour && d.pauseTime < 45*time.Minute { - if d.workTime <= (9*time.Hour) && d.pauseTime < 30*time.Minute { - diff := 30*time.Minute - d.pauseTime - d.workTime -= diff - d.pauseTime += diff - } else if d.pauseTime < 45*time.Minute { - diff := 45*time.Minute - d.pauseTime - d.workTime -= diff - d.pauseTime += diff - } +func (d *WorkDay) CalcWorkPauseDiff(user User) (work, pause time.Duration) { + if d.workTime == 0 { + d.CalcRealWorkTime(user) } + if d.Absence.AbwesenheitTyp.WorkTime > 0 { + return d.workTime, d.pauseTime + } + if d.workTime <= 6*time.Hour || d.pauseTime > 45*time.Minute { + return d.workTime, d.pauseTime + } + if d.workTime <= (9*time.Hour) && d.pauseTime < 30*time.Minute { + diff := 30*time.Minute - d.pauseTime + d.workTime -= diff + d.pauseTime += diff + } else if d.pauseTime < 45*time.Minute { + diff := 45*time.Minute - d.pauseTime + d.workTime -= diff + d.pauseTime += diff + } + + return d.workTime, d.pauseTime } -// Gets the duration someone worked that day -func (d *WorkDay) getWorkTime() { - if len(d.Bookings) < 1 { - return +func (d *WorkDay) CalcRealWorkTime(user User) time.Duration { + if (len(d.Bookings) < 1 && d.Absence == Absence{}) { + return 0 } - var workTime, pauseTime time.Duration + var realWorkTime, realPauseTime time.Duration var lastBooking Booking for _, booking := range d.Bookings { if booking.CheckInOut%2 == 1 { if !lastBooking.Timestamp.IsZero() { - pauseTime += booking.Timestamp.Sub(lastBooking.Timestamp) + realPauseTime += booking.Timestamp.Sub(lastBooking.Timestamp) } } else { - workTime += booking.Timestamp.Sub(lastBooking.Timestamp) + realWorkTime += booking.Timestamp.Sub(lastBooking.Timestamp) } lastBooking = booking } - // checks if booking is today and has no gehen yet, so the time since last kommen booking is added to workTime - if d.Day.Day() == time.Now().Day() && len(d.Bookings)%2 == 1 { - workTime += time.Since(lastBooking.Timestamp.Local()) + if helper.IsSameDate(d.Day, time.Now()) && len(d.Bookings)%2 == 1 { + realWorkTime += time.Since(lastBooking.Timestamp.Local()) } - d.workTime = workTime - d.pauseTime = pauseTime + if d.Absence.AbwesenheitTyp.WorkTime > 0 { + realWorkTime = time.Duration(user.ArbeitszeitPerTag * float32(time.Hour)).Round(time.Minute) + log.Println("Rewriting worktime", realWorkTime) + } + d.workTime = realWorkTime + d.pauseTime = realPauseTime - d.calcPauseTime() + return realWorkTime } func (d *WorkDay) GetWorkTimeString() (work string, pause string) { @@ -195,6 +205,10 @@ func (d *WorkDay) GetWorkTimeString() (work string, pause string) { return workString, pauseString } +func (d *WorkDay) GetAllWorkTimes(user User) (work, pause, overtime time.Duration) { + return d.workTime.Round(time.Minute), d.pauseTime.Round(time.Minute), d.CalcOvertime(user) +} + // returns bool wheter the workday was ended with an automatic logout func (d *WorkDay) RequiresAction() bool { if len(d.Bookings) == 0 { @@ -211,15 +225,13 @@ func (d *WorkDay) GetWorkDayProgress(user User) uint8 { } func (d *WorkDay) CalcOvertime(user User) time.Duration { + if d.workTime == 0 { + d.CalcWorkPauseDiff(user) + } if helper.IsWeekend(d.Day) && len(d.Bookings) == 0 { return 0 } var overtime time.Duration overtime = d.workTime - time.Duration(user.ArbeitszeitPerTag*float32(time.Hour)).Round(time.Minute) - // weekday is WE - if (d.Absence != Absence{}) { - overtime = 0 - } - return overtime } diff --git a/Backend/models/workDay_test.go b/Backend/models/workDay_test.go new file mode 100644 index 0000000..5b26ea7 --- /dev/null +++ b/Backend/models/workDay_test.go @@ -0,0 +1,82 @@ +package models_test + +import ( + "arbeitszeitmessung/helper" + "arbeitszeitmessung/models" + "log" + "testing" + "time" +) + +func CatchError[T any](val T, err error) T { + if err != nil { + log.Fatalln(err) + } + return val +} + +var testWorkDay = models.WorkDay{ + Day: CatchError(time.Parse("2006-01-02", "2025-01-01")), + Bookings: testBookings8hrs, + TimeFrom: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 08:00")), + TimeTo: CatchError(time.Parse("2006-01-02 15:04", "2025-01-01 16:30")), + Absence: models.Absence{}, +} + +func TestCalcRealWorkTime(t *testing.T) { + workTime := testWorkDay.CalcRealWorkTime(testUser) + if workTime != time.Hour*8 { + t.Errorf("Calc Worktime Default not working, time should be 8h, but was %s", helper.FormatDuration(workTime)) + } +} + +func TestCalcWorkPauseDiff(t *testing.T) { + type testCase struct { + Name string + bookings []models.Booking + expectedWorkTime time.Duration + expectedPauseTime time.Duration + expectedOvertime time.Duration + } + + testCases := []testCase{testCase{ + Name: "6hrs no pause", + bookings: testBookings6hrs, + expectedWorkTime: 6 * time.Hour, + expectedPauseTime: 0, + expectedOvertime: -2 * time.Hour, + }, + testCase{ + Name: "8hrs - 30min pause", + bookings: testBookings8hrs, + expectedWorkTime: 7*time.Hour + 30*time.Minute, + expectedPauseTime: 30 * time.Minute, + expectedOvertime: -30 * time.Minute, + }, + testCase{ + Name: "10hrs - 45min pause", + bookings: testBookings10hrs, + expectedWorkTime: 9*time.Hour + 15*time.Minute, + expectedPauseTime: 45 * time.Minute, + expectedOvertime: 1*time.Hour + 15*time.Minute, + }} + + for _, test := range testCases { + t.Run(test.Name, func(t *testing.T) { + testWorkDay.Bookings = test.bookings + testWorkDay.CalcRealWorkTime(testUser) + testWorkDay.CalcWorkPauseDiff(testUser) + testWorkDay.CalcOvertime(testUser) + workTime, pauseTime, overTime := testWorkDay.GetAllWorkTimes(testUser) + if workTime != test.expectedWorkTime { + t.Errorf("Calculated wrong workTime: should be %s, but was %s", helper.FormatDuration(test.expectedWorkTime), helper.FormatDuration(workTime)) + } + if pauseTime != test.expectedPauseTime { + t.Errorf("Calculated wrong pauseTime: should be %s, but was %s", helper.FormatDuration(test.expectedPauseTime), helper.FormatDuration(pauseTime)) + } + if overTime != test.expectedOvertime { + t.Errorf("Calculated wrong overtime: should be %s, but was %s", helper.FormatDuration(test.expectedOvertime), helper.FormatDuration(overTime)) + } + }) + } +} -- 2.49.1 From 2d0b117403dca38bf2b925f2f459e2ab8958c13b Mon Sep 17 00:00:00 2001 From: tom Date: Sat, 13 Sep 2025 14:12:39 +0200 Subject: [PATCH 2/3] added Gleitzeit + Kurzarbeit closes #23 --- Backend/endpoints/pdf.go | 4 +- Backend/endpoints/time.go | 81 +------ Backend/go.mod | 1 + Backend/go.sum | 4 +- Backend/helper/time.go | 13 +- Backend/models/absence.go | 2 +- Backend/models/booking.go | 32 --- Backend/models/db_test.go | 3 + Backend/models/user.go | 11 - Backend/models/workWeek.go | 11 +- Backend/models/workWeek_test.go | 1 + Backend/static/css/styles.css | 48 ++-- Backend/templates/headerComponent_templ.go | 2 +- Backend/templates/pages_templ.go | 2 +- Backend/templates/pdf.templ | 64 +++-- Backend/templates/pdf_templ.go | 270 +++++++++++++++------ Backend/templates/teamComponents_templ.go | 2 +- Backend/templates/timeComponents_templ.go | 2 +- 18 files changed, 298 insertions(+), 255 deletions(-) diff --git a/Backend/endpoints/pdf.go b/Backend/endpoints/pdf.go index 0e47fcd..bc73be9 100644 --- a/Backend/endpoints/pdf.go +++ b/Backend/endpoints/pdf.go @@ -11,7 +11,7 @@ import ( func PDFHandler(w http.ResponseWriter, r *http.Request) { helper.RequiresLogin(Session, w, r) - startDate, err := time.Parse("2006-01-02", "2025-08-01") + startDate, err := time.Parse("2006-01-02", "2025-09-01") if err != nil { log.Println("Error") } @@ -22,7 +22,7 @@ func PDFHandler(w http.ResponseWriter, r *http.Request) { log.Println("Error getting user!") } - weeks := models.GetWorkDays(user.CardUID, startDate, endDate) + weeks := models.GetWorkDays(user, startDate, endDate) 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 93b2b74..bc03c3f 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 - workDays := models.GetWorkDays(user.CardUID, tsFrom, tsTo) + workDays := models.GetWorkDays(user, tsFrom, tsTo) sort.Slice(workDays, func(i, j int) bool { return workDays[i].Day.After(workDays[j].Day) }) @@ -182,82 +182,3 @@ func createAbsence(absenceType int, user models.User, loc *time.Location, r *htt return } } - -func getBookingsAPI(w http.ResponseWriter, r *http.Request) { - _user_pn := r.URL.Query().Get("personal_nummer") - user_pn, err := strconv.Atoi(_user_pn) - if err != nil { - log.Println("No personal numver found!") - http.Error(w, "No personal number found", http.StatusBadRequest) - return - } - - user, err := models.GetUserByPersonalNr(user_pn) - if err != nil { - log.Println("No user found with the given personal number!") - http.Error(w, "No user found", http.StatusNotFound) - return - } - - // TODO add config for timeoffset - tsFrom, err := parseTimestamp(r, "time_from", time.Now().AddDate(0, -1, 0).Format("2006-01-02")) - if err != nil { - log.Println("Error parsing 'from' time", err) - http.Error(w, "Timestamp 'from' cannot be parsed!", http.StatusBadRequest) - return - } - tsTo, err := parseTimestamp(r, "time_to", time.Now().Format("2006-01-02")) - if err != nil { - log.Println("Error parsing 'to' time", err) - http.Error(w, "Timestamp 'to' cannot be parsed!", http.StatusBadRequest) - return - } - tsTo = tsTo.AddDate(0, 0, 1) // so that today is inside - - bookings, err := (*models.Booking).GetBookingsGrouped(nil, user.CardUID, tsFrom, tsTo) - if err != nil { - log.Println("Error getting bookings: ", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(bookings) -} - -// Updates a booking form the given json body -func updateBookingAPI(w http.ResponseWriter, r *http.Request) { - _booking_id := r.URL.Query().Get("counter_id") - if _booking_id == "" { - http.Error(w, "Missing bookingID query parameter", http.StatusBadRequest) - return - } - booking_id, err := strconv.Atoi(_booking_id) - if err != nil { - http.Error(w, "Invalid bookingID query parameter", http.StatusBadRequest) - return - } - bookingDB, err := (*models.Booking).GetBookingById(nil, booking_id) - if err != nil { - log.Println("Error getting booking: ", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - var booking models.Booking - dec := json.NewDecoder(r.Body) - dec.DisallowUnknownFields() - err = dec.Decode(&booking) - if err != nil { - log.Println("Error parsing booking: ", err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - if booking.CounterId != 0 && booking.CounterId != bookingDB.CounterId { - log.Println("Booking Ids do not match") - http.Error(w, "Booking Ids do not match", http.StatusBadRequest) - return - } - bookingDB.Update(booking) - bookingDB.Save() - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(bookingDB) -} diff --git a/Backend/go.mod b/Backend/go.mod index 2472dc8..b993a01 100644 --- a/Backend/go.mod +++ b/Backend/go.mod @@ -17,4 +17,5 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect go.uber.org/atomic v1.7.0 // indirect + golang.org/x/sys v0.36.0 // indirect ) diff --git a/Backend/go.sum b/Backend/go.sum index 82a9cc4..6c7522d 100644 --- a/Backend/go.sum +++ b/Backend/go.sum @@ -68,7 +68,7 @@ go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt3 go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/Backend/helper/time.go b/Backend/helper/time.go index 0bd5551..046ad64 100644 --- a/Backend/helper/time.go +++ b/Backend/helper/time.go @@ -25,8 +25,12 @@ func GetKW(t time.Time) int { return kw } -// Converts duration to string func FormatDuration(d time.Duration) string { + return FormatDurationFill(d, false) +} + +// Converts duration to string +func FormatDurationFill(d time.Duration, fill bool) string { hours := int(d.Abs().Hours()) minutes := int(d.Abs().Minutes()) % 60 sign := "" @@ -41,6 +45,13 @@ func FormatDuration(d time.Duration) string { case minutes > 0: return fmt.Sprintf("%s%dmin", sign, minutes) default: + if fill { + return "0min" + } return "" } } + +func IsSameDate(a, b time.Time) bool { + return a.Truncate(24 * time.Hour).Equal(b.Truncate(24 * time.Hour)) +} diff --git a/Backend/models/absence.go b/Backend/models/absence.go index bda305e..08919f4 100644 --- a/Backend/models/absence.go +++ b/Backend/models/absence.go @@ -9,7 +9,7 @@ import ( type AbsenceType struct { Id int8 Name string - WorkTime float32 + WorkTime int8 } type Absence struct { diff --git a/Backend/models/booking.go b/Backend/models/booking.go index ba758f8..7b4d356 100644 --- a/Backend/models/booking.go +++ b/Backend/models/booking.go @@ -7,7 +7,6 @@ import ( "fmt" "log" "net/url" - "sort" "strconv" "time" ) @@ -163,37 +162,6 @@ func (b *Booking) GetBookingsByCardID(card_uid string, tsFrom time.Time, tsTo ti return bookings, nil } -func (b *Booking) GetBookingsGrouped(card_uid string, tsFrom time.Time, tsTo time.Time) ([]WorkDay, error) { - var grouped = make(map[string][]Booking) - bookings, err := b.GetBookingsByCardID(card_uid, tsFrom, tsTo) - if err != nil { - log.Println("Failed to get bookings", err) - return []WorkDay{}, nil - } - for _, booking := range bookings { - day := booking.Timestamp.Truncate(24 * time.Hour) - key := day.Format("2006-01-02") - grouped[key] = append(grouped[key], booking) - } - - var result []WorkDay - for key, bookings := range grouped { - day, _ := time.Parse("2006-01-02", key) - sort.Slice(bookings, func(i, j int) bool { - return bookings[i].Timestamp.Before(bookings[j].Timestamp) - }) - workDay := WorkDay{Day: day, Bookings: bookings} - workDay.getWorkTime() - result = append(result, workDay) - } - - sort.Slice(result, func(i, j int) bool { - return result[i].Day.After(result[j].Day) - }) - - return result, nil -} - func (b Booking) Save() { qStr, err := DB.Prepare((`UPDATE "anwesenheit" SET "card_uid" = $2, "geraet_id" = $3, "check_in_out" = $4, "timestamp" = $5 WHERE "counter_id" = $1;`)) if err != nil { diff --git a/Backend/models/db_test.go b/Backend/models/db_test.go index be272c5..b2afa0f 100644 --- a/Backend/models/db_test.go +++ b/Backend/models/db_test.go @@ -22,6 +22,9 @@ type DBFixture struct { func SetupDBFixture(t *testing.T) *DBFixture { t.Helper() + if helper.GetEnv("TEST_SQL", "false") != "true" { + t.Skip("Skipping Test because TEST_SQL is not 'true'!") + } dbHost := helper.GetEnv("POSTGRES_HOST", "localhost") dbPort := helper.GetEnv("POSTGRES_PORT", "5433") diff --git a/Backend/models/user.go b/Backend/models/user.go index 016d683..b7002d2 100644 --- a/Backend/models/user.go +++ b/Backend/models/user.go @@ -198,17 +198,6 @@ func (u *User) IsTeamLeader() bool { return len(team) > 0 } -func (u *User) GetWeek(tsFrom time.Time) WorkWeek { - var bookings []WorkDay - weekStart := tsFrom.AddDate(0, 0, -1*int(tsFrom.Local().Weekday())-1) - bookings, err := (*Booking).GetBookingsGrouped(nil, u.CardUID, weekStart, time.Now()) - if err != nil { - log.Println("Error fetching bookings!") - return WorkWeek{WorkDays: bookings} - } - return WorkWeek{WorkDays: bookings} -} - // gets the first week, that needs to be submitted func (u *User) GetNextWeek() WorkWeek { var week WorkWeek diff --git a/Backend/models/workWeek.go b/Backend/models/workWeek.go index cb473d2..fb7d6a7 100644 --- a/Backend/models/workWeek.go +++ b/Backend/models/workWeek.go @@ -45,7 +45,7 @@ func NewWorkWeek(user User, tsMonday time.Time, populate bool) WorkWeek { } func (w *WorkWeek) PopulateWithBookings(worktime time.Duration, overtime time.Duration) { - w.WorkDays = GetWorkDays(w.User.CardUID, w.WeekStart, w.WeekStart.Add(7*24*time.Hour)) + w.WorkDays = GetWorkDays(w.User, w.WeekStart, w.WeekStart.Add(7*24*time.Hour)) if absences, err := GetAbsencesByCardUID(w.User.CardUID, w.WeekStart, w.WeekStart.Add(7*24*time.Hour)); err == nil { w.Absences = absences } else { @@ -108,10 +108,11 @@ func (w *WorkWeek) aggregateWorkTime() time.Duration { for _, day := range w.WorkDays { workTime += day.workTime } - for _, absences := range w.Absences { - absenceWorkTime := absences.AbwesenheitTyp.WorkTime - (absences.AbwesenheitTyp.WorkTime - w.User.ArbeitszeitPerTag) // workTime Equivalent of Absence is capped at user Worktime per Day - workTime += time.Duration(absenceWorkTime * float32(time.Hour)).Round(time.Minute) - } + // for _, absence := range w.Absences { + // log.Println(absence) + // absenceWorkTime := float32(8) // := absences.AbwesenheitTyp.WorkTime - (absences.AbwesenheitTyp.WorkTime - w.User.ArbeitszeitPerTag) // workTime Equivalent of Absence is capped at user Worktime per Day + // workTime += time.Duration(absenceWorkTime * float32(time.Hour)).Round(time.Minute) + // } return workTime } diff --git a/Backend/models/workWeek_test.go b/Backend/models/workWeek_test.go index b94dd04..cd78cef 100644 --- a/Backend/models/workWeek_test.go +++ b/Backend/models/workWeek_test.go @@ -28,6 +28,7 @@ func TestNewWorkWeekNoPopulate(t *testing.T) { } func TestCheckStatus(t *testing.T) { + SetupDBFixture(t) testWeek := SetupWorkWeekFixture(t) testCases := []struct { name string diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css index 93e47a6..bd88eca 100644 --- a/Backend/static/css/styles.css +++ b/Backend/static/css/styles.css @@ -198,12 +198,12 @@ .col-span-3 { grid-column: span 3 / span 3; } + .col-span-5 { + grid-column: span 5 / span 5; + } .col-span-6 { grid-column: span 6 / span 6; } - .col-span-7 { - grid-column: span 7 / span 7; - } .col-span-full { grid-column: 1 / -1; } @@ -367,17 +367,17 @@ .resize { resize: both; } + .auto-rows-min { + grid-auto-rows: min-content; + } .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .grid-cols-\[auto_1fr_1fr_1fr_1fr_1fr\] { - grid-template-columns: auto 1fr 1fr 1fr 1fr 1fr; - } - .grid-cols-\[auto_1fr_1fr_1fr_1fr_1fr_1fr\] { - grid-template-columns: auto 1fr 1fr 1fr 1fr 1fr 1fr; + .grid-cols-\[3fr_2fr_2fr_2fr_3fr_3fr_3fr\] { + grid-template-columns: 3fr 2fr 2fr 2fr 3fr 3fr 3fr; } .grid-cols-subgrid { grid-template-columns: subgrid; @@ -432,6 +432,11 @@ border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); } } + .divide-neutral-300 { + :where(& > :not(:last-child)) { + border-color: var(--color-neutral-300); + } + } .justify-self-end { justify-self: flex-end; } @@ -448,6 +453,14 @@ border-style: var(--tw-border-style); border-width: 1px; } + .border-r-0 { + border-right-style: var(--tw-border-style); + border-right-width: 0px; + } + .border-b-0 { + border-bottom-style: var(--tw-border-style); + border-bottom-width: 0px; + } .border-neutral-200 { border-color: var(--color-neutral-200); } @@ -481,9 +494,6 @@ .mask-repeat { mask-repeat: repeat; } - .p-0 { - padding: calc(var(--spacing) * 0); - } .p-1 { padding: calc(var(--spacing) * 1); } @@ -493,9 +503,6 @@ .p-8 { padding: calc(var(--spacing) * 8); } - .px-2 { - padding-inline: calc(var(--spacing) * 2); - } .px-3 { padding-inline: calc(var(--spacing) * 3); } @@ -530,6 +537,9 @@ .text-accent { color: var(--color-accent); } + .text-neutral-300 { + color: var(--color-neutral-300); + } .text-neutral-500 { color: var(--color-neutral-500); } @@ -572,6 +582,16 @@ --tw-duration: 300ms; transition-duration: 300ms; } + .\*\:p-2 { + :is(& > *) { + padding: calc(var(--spacing) * 2); + } + } + .\*\:text-center { + :is(& > *) { + text-align: center; + } + } .group-hover\:text-black { &:is(:where(.group):hover *) { @media (hover: hover) { diff --git a/Backend/templates/headerComponent_templ.go b/Backend/templates/headerComponent_templ.go index 44846c8..8e59160 100644 --- a/Backend/templates/headerComponent_templ.go +++ b/Backend/templates/headerComponent_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.833 +// templ: version: v0.3.943 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/Backend/templates/pages_templ.go b/Backend/templates/pages_templ.go index c0d73e3..d546e65 100644 --- a/Backend/templates/pages_templ.go +++ b/Backend/templates/pages_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.833 +// templ: version: v0.3.943 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/Backend/templates/pdf.templ b/Backend/templates/pdf.templ index 2aacb05..8ffe9cc 100644 --- a/Backend/templates/pdf.templ +++ b/Backend/templates/pdf.templ @@ -1,14 +1,15 @@ package templates import ( - "arbeitszeitmessung/models" "arbeitszeitmessung/helper" + "arbeitszeitmessung/models" "time" ) templ PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Time, tsEnd time.Time) { {{ _, kw := tsStart.ISOWeek() + noBorder := "" }} @Base() @@ -18,33 +19,50 @@ templ PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Ti

Arbeitszeit:

Überstunden:

-
-

{ kw }

-

Kommen

-

Gehen

-

Arbeitsart

-

Stunden gesamt

-

Pause

-

Überstunden

- for _, day := range workDays{ +
+

{ kw }

+

Kommen

+

Gehen

+

Arbeitsart

+

Stunden

+

Pause

+

Überstunden

+ for index, day := range workDays { + {{ + if index == len(workDays)-1 { + noBorder = "border-b-0" + } + }} if day.Day.Weekday() == time.Monday { -

Wochenende

+

Wochenende

} -

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

+

{ day.Day.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 }

- } +
+ 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.Absence != models.Absence{}) { +

{ day.Absence.AbwesenheitTyp.Name }

+ }
- {{ work, pause := day.GetWorkTimeString() }} -

{ work }

-

{ pause }

-

{ helper.FormatDuration(day.CalcOvertime(e)) }

+ {{ work, pause, overtime := day.GetAllWorkTimes(e) }} + @ColorDuration(work, noBorder) + @ColorDuration(pause, noBorder) + @ColorDuration(overtime, noBorder + " border-r-0") } -
} + +templ ColorDuration(d time.Duration, classes string){ +{{ + color := "" + if d.Abs() < time.Minute{ + color = "text-neutral-300" + } +}} +

{ helper.FormatDurationFill(d, true) }

+} diff --git a/Backend/templates/pdf_templ.go b/Backend/templates/pdf_templ.go index 5430b0f..ca73f9d 100644 --- a/Backend/templates/pdf_templ.go +++ b/Backend/templates/pdf_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.833 +// templ: version: v0.3.943 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -37,6 +37,7 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim ctx = templ.ClearChildren(ctx) _, kw := tsStart.ISOWeek() + noBorder := "" templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err @@ -48,7 +49,7 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(tsStart.Format("02.01.2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 17, Col: 52} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 18, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { @@ -61,148 +62,257 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(tsEnd.Format("02.01.2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 17, Col: 98} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 18, Col: 98} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

Arbeitszeit:

Überstunden:

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

Arbeitszeit:

Überstunden:

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(kw) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 22, Col: 34} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 23, Col: 19} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

Kommen

Gehen

Arbeitsart

Stunden gesamt

Pause

Überstunden

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

Kommen

Gehen

Arbeitsart

Stunden

Pause

Überstunden

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - for _, day := range workDays { + for index, day := range workDays { + + if index == len(workDays)-1 { + noBorder = "border-b-0" + } if day.Day.Weekday() == time.Monday { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

Wochenende

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

Wochenende

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

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var5 string - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 33, Col: 61} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + var templ_7745c5c3_Var5 = []any{noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

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

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, 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: 37, Col: 82} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, 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: 38, Col: 84} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var8 string - templ_7745c5c3_Var8, 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: 39, Col: 73} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) - 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_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var5).String()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 1, Col: 0} } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - work, pause := day.GetWorkTimeString() - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 39, Col: 56} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 = []any{"grid grid-cols-subgrid col-span-3 " + noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(pause) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 44, Col: 39} + for bookingI := 0; bookingI < len(day.Bookings); bookingI += 2 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") + 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: 43, Col: 59} + } + _, 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, 13, "

") + 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: 44, 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, 14, "

") + 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: 45, 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, 15, "

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

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 48, Col: 64} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + 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, 18, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "

") + work, pause, overtime := day.GetAllWorkTimes(e) + templ_7745c5c3_Err = ColorDuration(work, noBorder).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(day.CalcOvertime(e))) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 45, Col: 76} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

") + templ_7745c5c3_Err = ColorDuration(pause, noBorder).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ColorDuration(overtime, noBorder+" border-r-0").Render(ctx, templ_7745c5c3_Buffer) 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 + } + return nil + }) +} + +func ColorDuration(d time.Duration, classes string) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var14 := templ.GetChildren(ctx) + if templ_7745c5c3_Var14 == nil { + templ_7745c5c3_Var14 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + + color := "" + if d.Abs() < time.Minute { + color = "text-neutral-300" + } + 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, 22, "

") + 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: 67, Col: 71} + } + _, 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, 24, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/teamComponents_templ.go b/Backend/templates/teamComponents_templ.go index 9dd6ee3..239425d 100644 --- a/Backend/templates/teamComponents_templ.go +++ b/Backend/templates/teamComponents_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.833 +// templ: version: v0.3.943 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/Backend/templates/timeComponents_templ.go b/Backend/templates/timeComponents_templ.go index aca6f54..47896fd 100644 --- a/Backend/templates/timeComponents_templ.go +++ b/Backend/templates/timeComponents_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.833 +// templ: version: v0.3.943 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. -- 2.49.1 From 656d4c2340d0f4fb5c360607037101c1d22482be Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 15 Sep 2025 12:33:46 +0200 Subject: [PATCH 3/3] small fixes in pdf generation + time calculation --- Backend/endpoints/pdf.go | 13 +- Backend/models/workDay.go | 1 - Backend/src/main.css | 191 +++---- Backend/static/css/styles.css | 108 ++-- Backend/templates/pdf.templ | 156 +++++- Backend/templates/pdf_templ.go | 604 +++++++++++++++++++--- Backend/templates/timeComponents.templ | 2 +- Backend/templates/timeComponents_templ.go | 4 +- 8 files changed, 865 insertions(+), 214 deletions(-) diff --git a/Backend/endpoints/pdf.go b/Backend/endpoints/pdf.go index bc73be9..50f7130 100644 --- a/Backend/endpoints/pdf.go +++ b/Backend/endpoints/pdf.go @@ -11,9 +11,14 @@ import ( func PDFHandler(w http.ResponseWriter, r *http.Request) { helper.RequiresLogin(Session, w, r) - startDate, err := time.Parse("2006-01-02", "2025-09-01") + startDate, err := parseTimestamp(r, "start", time.Now().Format("2006-01-02")) if err != nil { - log.Println("Error") + log.Println("Error parsing 'start_date' time", err) + http.Error(w, "Timestamp 'start_date' cannot be parsed!", http.StatusBadRequest) + return + } + if startDate.Day() > 1 { + startDate = startDate.AddDate(0, 0, -(startDate.Day() - 1)) } endDate := startDate.AddDate(0, 1, -1) @@ -22,8 +27,10 @@ func PDFHandler(w http.ResponseWriter, r *http.Request) { log.Println("Error getting user!") } + //TODO: only accepted weeks + weeks := models.GetWorkDays(user, startDate, endDate) - log.Printf("Using Dates: %s - %s\n", startDate.String(), endDate.String()) + // 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/models/workDay.go b/Backend/models/workDay.go index fda0704..e5cf71e 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -191,7 +191,6 @@ func (d *WorkDay) CalcRealWorkTime(user User) time.Duration { } if d.Absence.AbwesenheitTyp.WorkTime > 0 { realWorkTime = time.Duration(user.ArbeitszeitPerTag * float32(time.Hour)).Round(time.Minute) - log.Println("Rewriting worktime", realWorkTime) } d.workTime = realWorkTime d.pauseTime = realPauseTime diff --git a/Backend/src/main.css b/Backend/src/main.css index f2b68f0..85ae31e 100644 --- a/Backend/src/main.css +++ b/Backend/src/main.css @@ -1,107 +1,120 @@ @import "tailwindcss"; @source "../templates/*.templ"; @plugin "@iconify/tailwind4" { - scale: 1.5; + scale: 1.25; } @theme { - --color-accent-50: #e7fdea; - --color-accent-100: #cbfbd1; - --color-accent-200: #9cf7a8; - --color-accent-300: #68f37a; - --color-accent-400: #33ef4d; - --color-accent-500: #11db2d; - --color-accent-600: #0eaf23; - --color-accent-700: #0a851b; - --color-accent-800: #075a12; - --color-accent-900: #032b09; - --color-accent-950: #021805; - --color-accent: #0eaf23; - --color-text-50: #f7f8f7; - --color-text-100: #f2f3f2; - --color-text-200: #e2e4e2; - --color-text-300: #d2d6d2; - --color-text-400: #c2c7c2; - --color-text-500: #afb6af; - --color-text-600: #97a097; - --color-text-700: #7d877d; - --color-text-800: #5a625a; - --color-text-900: #161816; - --color-text-950: #000000; + --color-accent-50: #e7fdea; + --color-accent-100: #cbfbd1; + --color-accent-200: #9cf7a8; + --color-accent-300: #68f37a; + --color-accent-400: #33ef4d; + --color-accent-500: #11db2d; + --color-accent-600: #0eaf23; + --color-accent-700: #0a851b; + --color-accent-800: #075a12; + --color-accent-900: #032b09; + --color-accent-950: #021805; + --color-accent: #0eaf23; + --color-text-50: #f7f8f7; + --color-text-100: #f2f3f2; + --color-text-200: #e2e4e2; + --color-text-300: #d2d6d2; + --color-text-400: #c2c7c2; + --color-text-500: #afb6af; + --color-text-600: #97a097; + --color-text-700: #7d877d; + --color-text-800: #5a625a; + --color-text-900: #161816; + --color-text-950: #000000; +} + +@layer base { + body { + -webkit-print-color-adjust: exact !important; + print-color-adjust: exact !important; + } } @layer components { - .grid-main { - display: grid; - grid-template-columns: 2fr auto 1fr; - align-items: stretch; - } + .grid-main { + display: grid; + grid-template-columns: 2fr auto 1fr; + align-items: stretch; + } - .grid-sub { - display: grid; - grid-template-columns: subgrid; - grid-column: 1 / -1; - border-color: var(--color-neutral-400); - transition: background-color 0.2s ease-in-out; + .grid-sub { + display: grid; + grid-template-columns: subgrid; + grid-column: 1 / -1; + border-color: var(--color-neutral-400); + transition: background-color 0.2s ease-in-out; + } + + .grid-sub.responsive { + display: flex; + flex-direction: column; + } + + .grid-sub:hover { + background-color: var(--color-neutral-200); + } + + .grid-cell { + padding: calc(var(--spacing) * 2); + border-color: var(--color-neutral-400); + } + + .btn { + width: 100%; + cursor: pointer; + border-radius: var(--radius-md); + color: var(--color-neutral-800); + font-size: var(--text-sm); + text-align: center; + padding: calc(var(--spacing) * 2); + border-style: var(--tw-border-style); + border-width: 1px; + border-color: var(--color-neutral-800); + transition-property: + color, background-color, border-color, outline-color, + text-decoration-color, fill, stroke, --tw-gradient-from, + --tw-gradient-via, --tw-gradient-to; + transition-timing-function: var( + --tw-ease, + var(--default-transition-timing-function) + ); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + + .btn:hover { + color: var(--color-white); + background-color: var(--color-neutral-700); + } + + .btn:disabled { + opacity: 50%; + pointer-events: none; + } + + .btn:active, + .btn:focus { + background-color: var(--color-neutral-700); + } + + @media (width >=48rem) { + .grid-main { + grid-template-columns: repeat(5, 1fr); + margin: 0 10%; } .grid-sub.responsive { - display: flex; - flex-direction: column; - } - - .grid-sub:hover { - background-color: var(--color-neutral-200); - } - - .grid-cell { - padding: calc(var(--spacing) * 2); - border-color: var(--color-neutral-400); + display: grid; } .btn { - width: 100%; - cursor: pointer; - border-radius: var(--radius-md); - color: var(--color-neutral-800); - font-size: var(--text-sm); - text-align: center; - padding: calc(var(--spacing) * 2); - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-neutral-800); - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - } - - .btn:hover { - color: var(--color-white); - background-color: var(--color-neutral-700); - } - - .btn:disabled { - opacity: 50%; - pointer-events: none; - } - - .btn:active, - .btn:focus { - background-color: var(--color-neutral-700); - } - - @media (width >=48rem) { - .grid-main { - grid-template-columns: repeat(5, 1fr); - margin: 0 10%; - } - - .grid-sub.responsive { - display: grid; - } - - .btn { - padding-inline: calc(var(--spacing) * 4); - } + padding-inline: calc(var(--spacing) * 4); } + } } diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css index bd88eca..53202ab 100644 --- a/Backend/static/css/styles.css +++ b/Backend/static/css/styles.css @@ -16,6 +16,7 @@ --color-neutral-300: oklch(87% 0 0); --color-neutral-400: oklch(70.8% 0 0); --color-neutral-500: oklch(55.6% 0 0); + --color-neutral-600: oklch(43.9% 0 0); --color-neutral-700: oklch(37.1% 0 0); --color-neutral-800: oklch(26.9% 0 0); --color-neutral-900: oklch(20.5% 0 0); @@ -198,12 +199,6 @@ .col-span-3 { grid-column: span 3 / span 3; } - .col-span-5 { - grid-column: span 5 / span 5; - } - .col-span-6 { - grid-column: span 6 / span 6; - } .col-span-full { grid-column: 1 / -1; } @@ -221,8 +216,8 @@ } .icon-\[material-symbols-light--add-circle-outline\] { display: inline-block; - width: 1.5em; - height: 1.5em; + width: 1.25em; + height: 1.25em; background-color: currentColor; -webkit-mask-image: var(--svg); mask-image: var(--svg); @@ -234,8 +229,8 @@ } .icon-\[material-symbols-light--check-circle-outline\] { display: inline-block; - width: 1.5em; - height: 1.5em; + width: 1.25em; + height: 1.25em; background-color: currentColor; -webkit-mask-image: var(--svg); mask-image: var(--svg); @@ -247,8 +242,8 @@ } .icon-\[material-symbols-light--circle-outline\] { display: inline-block; - width: 1.5em; - height: 1.5em; + width: 1.25em; + height: 1.25em; background-color: currentColor; -webkit-mask-image: var(--svg); mask-image: var(--svg); @@ -260,8 +255,8 @@ } .icon-\[material-symbols-light--more-time\] { display: inline-block; - width: 1.5em; - height: 1.5em; + width: 1.25em; + height: 1.25em; background-color: currentColor; -webkit-mask-image: var(--svg); mask-image: var(--svg); @@ -273,8 +268,8 @@ } .icon-\[material-symbols-light--motion-photos-paused-outline\] { display: inline-block; - width: 1.5em; - height: 1.5em; + width: 1.25em; + height: 1.25em; background-color: currentColor; -webkit-mask-image: var(--svg); mask-image: var(--svg); @@ -284,6 +279,19 @@ mask-size: 100% 100%; --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M9.808 14.616h1V9.385h-1zm3.384 0h1V9.385h-1zM12.003 21q-1.866 0-3.51-.705q-1.643-.706-2.859-1.915t-1.925-2.843T3 12.039q0-.905.167-1.778t.497-1.713l.78.78q-.219.65-.331 1.32T4 12q0 3.35 2.325 5.675T12 20t5.675-2.325T20 12t-2.325-5.675T12 4q-.675 0-1.332.112t-1.3.332l-.776-.775q.789-.315 1.606-.492T11.885 3q1.887 0 3.546.701t2.894 1.926t1.955 2.866t.72 3.505t-.708 3.509t-1.924 2.859t-2.856 1.925t-3.509.709M5.923 6.808q-.356 0-.62-.265q-.264-.264-.264-.62t.264-.62t.62-.264t.62.264t.265.62t-.265.62t-.62.265M12 12'/%3E%3C/svg%3E"); } + .icon-\[material-symbols-light--nest-clock-farsight-analog-outline\] { + display: inline-block; + width: 1.25em; + height: 1.25em; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M14.935 16.223L11.5 12.789V7.923h1v4.464l3.123 3.123zM11.5 6V4h1v2zm6.5 6.5v-1h2v1zM11.5 20v-2h1v2zM4 12.5v-1h2v1zm8.003 8.5q-1.867 0-3.51-.708q-1.643-.709-2.859-1.924t-1.925-2.856T3 12.003t.709-3.51Q4.417 6.85 5.63 5.634t2.857-1.925T11.997 3t3.51.709q1.643.708 2.859 1.922t1.925 2.857t.709 3.509t-.708 3.51t-1.924 2.859t-2.856 1.925t-3.509.709M12 20q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8'/%3E%3C/svg%3E"); + } .flex { display: flex; } @@ -322,15 +330,15 @@ .h-full { height: 100%; } + .w-1\/7 { + width: calc(1/7 * 100%); + } .w-2 { width: calc(var(--spacing) * 2); } .w-4 { width: calc(var(--spacing) * 4); } - .w-9 { - width: calc(var(--spacing) * 9); - } .w-9\/10 { width: calc(9/10 * 100%); } @@ -343,9 +351,6 @@ .w-full { width: 100%; } - .flex-shrink { - flex-shrink: 1; - } .flex-shrink-0 { flex-shrink: 0; } @@ -364,8 +369,8 @@ .cursor-pointer { cursor: pointer; } - .resize { - resize: both; + .break-after-page { + break-after: page; } .auto-rows-min { grid-auto-rows: min-content; @@ -453,10 +458,22 @@ border-style: var(--tw-border-style); border-width: 1px; } + .border-1 { + border-style: var(--tw-border-style); + border-width: 1px; + } + .border-t-1 { + border-top-style: var(--tw-border-style); + border-top-width: 1px; + } .border-r-0 { border-right-style: var(--tw-border-style); border-right-width: 0px; } + .border-r-1 { + border-right-style: var(--tw-border-style); + border-right-width: 1px; + } .border-b-0 { border-bottom-style: var(--tw-border-style); border-bottom-width: 0px; @@ -467,6 +484,9 @@ .border-neutral-300 { border-color: var(--color-neutral-300); } + .border-neutral-600 { + border-color: var(--color-neutral-600); + } .border-neutral-900 { border-color: var(--color-neutral-900); } @@ -491,9 +511,6 @@ .bg-red-600 { background-color: var(--color-red-600); } - .mask-repeat { - mask-repeat: repeat; - } .p-1 { padding: calc(var(--spacing) * 1); } @@ -558,13 +575,6 @@ .uppercase { text-transform: uppercase; } - .underline { - text-decoration-line: underline; - } - .outline { - outline-style: var(--tw-outline-style); - outline-width: 1px; - } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } @@ -582,9 +592,14 @@ --tw-duration: 300ms; transition-duration: 300ms; } - .\*\:p-2 { + .\*\:\*\:\*\:border-1 { :is(& > *) { - padding: calc(var(--spacing) * 2); + :is(& > *) { + :is(& > *) { + border-style: var(--tw-border-style); + border-width: 1px; + } + } } } .\*\:text-center { @@ -592,6 +607,13 @@ text-align: center; } } + .\*\:not-print\:p-2 { + :is(& > *) { + @media not print { + padding: calc(var(--spacing) * 2); + } + } + } .group-hover\:text-black { &:is(:where(.group):hover *) { @media (hover: hover) { @@ -852,6 +874,12 @@ } } } +@layer base { + body { + -webkit-print-color-adjust: exact !important; + print-color-adjust: exact !important; + } +} @layer components { .grid-main { display: grid; @@ -888,7 +916,7 @@ border-width: 1px; border-color: var(--color-neutral-800); transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-timing-function: var( --tw-ease, var(--default-transition-timing-function) ); transition-duration: var(--tw-duration, var(--default-transition-duration)); } .btn:hover { @@ -934,11 +962,6 @@ syntax: "*"; inherits: false; } -@property --tw-outline-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} @property --tw-blur { syntax: "*"; inherits: false; @@ -1003,7 +1026,6 @@ --tw-border-style: solid; --tw-divide-y-reverse: 0; --tw-font-weight: initial; - --tw-outline-style: solid; --tw-blur: initial; --tw-brightness: initial; --tw-contrast: initial; diff --git a/Backend/templates/pdf.templ b/Backend/templates/pdf.templ index 8ffe9cc..7779608 100644 --- a/Backend/templates/pdf.templ +++ b/Backend/templates/pdf.templ @@ -12,30 +12,27 @@ templ PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Ti noBorder := "" }} @Base() - +

Kim Mustermensch

Zeitraum: { tsStart.Format("02.01.2006") } - { tsEnd.Format("02.01.2006") }

Arbeitszeit:

Überstunden:

-
-

{ kw }

-

Kommen

-

Gehen

-

Arbeitsart

-

Stunden

-

Pause

-

Überstunden

+
+

{ kw }

+

Kommen

+

Gehen

+

Arbeitsart

+

Stunden

+

Pause

+

Überstunden

for index, day := range workDays { {{ if index == len(workDays)-1 { noBorder = "border-b-0" } }} - if day.Day.Weekday() == time.Monday { -

Wochenende

- }

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

@@ -52,11 +49,146 @@ templ PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Ti @ColorDuration(work, noBorder) @ColorDuration(pause, noBorder) @ColorDuration(overtime, noBorder + " border-r-0") + if day.Day.Weekday() == time.Friday { +

Wochenende

+ } }
} +templ PDFReportEmployeTable(e models.User, workDays []models.WorkDay, tsStart time.Time, tsEnd time.Time) { + {{ + _, kw := tsStart.ISOWeek() + noBorder := "" + }} + @Base() + +
+

Kim Mustermensch

+

Zeitraum: { tsStart.Format("02.01.2006") } - { tsEnd.Format("02.01.2006") }

+

Arbeitszeit:

+

Überstunden:

+
+ + + + + + + + + + + for index, day := range workDays { + {{ + if index == len(workDays)-1 { + noBorder = "border-b-0" + } + }} + + + + {{ work, pause, overtime := day.GetAllWorkTimes(e) }} + @ColorDuration(work, noBorder) + @ColorDuration(pause, noBorder) + @ColorDuration(overtime, noBorder + " border-r-0") + if day.Day.Weekday() == time.Friday { + + + + } + + } +
{ kw }KommenGehenArbeitsartStundenPauseÜberstunden
{ day.Day.Format("02.01.2006") } + + for bookingI := 0; bookingI < len(day.Bookings); bookingI+= 2 { + + + + + + } + if (day.Absence != models.Absence{}) { + if len(day.Bookings) > 0 { + + + + } + else { + + + + } + + } +
{ day.Bookings[bookingI].Timestamp.Format("15:04") }{ day.Bookings[bookingI+1].Timestamp.Format("15:04") }{ day.Bookings[bookingI].BookingType.Name }
{ day.Absence.AbwesenheitTyp.Name }
{ day.Absence.AbwesenheitTyp.Name }
+
Wochenende
+
+
+
+

Kim Mustermensch

+

Zeitraum: { tsStart.Format("02.01.2006") } - { tsEnd.Format("02.01.2006") }

+

Arbeitszeit:

+

Überstunden:

+
+ + + + + + + + + + + for index, day := range workDays { + {{ + if index == len(workDays)-1 { + noBorder = "border-b-0" + } + }} + + + + {{ work, pause, overtime := day.GetAllWorkTimes(e) }} + @ColorDuration(work, noBorder) + @ColorDuration(pause, noBorder) + @ColorDuration(overtime, noBorder + " border-r-0") + if day.Day.Weekday() == time.Friday { + + + + } + + } +
{ kw }KommenGehenArbeitsartStundenPauseÜberstunden
{ day.Day.Format("02.01.2006") } + + for bookingI := 0; bookingI < len(day.Bookings); bookingI+= 2 { + + + + + + } + if (day.Absence != models.Absence{}) { + if len(day.Bookings) > 0 { + + + + } + else { + + + + } + + } +
{ day.Bookings[bookingI].Timestamp.Format("15:04") }{ day.Bookings[bookingI+1].Timestamp.Format("15:04") }{ day.Bookings[bookingI].BookingType.Name }
{ day.Absence.AbwesenheitTyp.Name }
{ day.Absence.AbwesenheitTyp.Name }
+
Wochenende
+
+} + templ ColorDuration(d time.Duration, classes string){ {{ color := "" diff --git a/Backend/templates/pdf_templ.go b/Backend/templates/pdf_templ.go index ca73f9d..1f429a0 100644 --- a/Backend/templates/pdf_templ.go +++ b/Backend/templates/pdf_templ.go @@ -42,7 +42,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, 1, "

Kim Mustermensch

Zeitraum: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

Kim Mustermensch

Zeitraum: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -68,20 +68,20 @@ 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, 3, "

Arbeitszeit:

Überstunden:

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

Arbeitszeit:

Überstunden:

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(kw) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 23, Col: 19} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 23, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

Kommen

Gehen

Arbeitsart

Stunden

Pause

Überstunden

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

Kommen

Gehen

Arbeitsart

Stunden

Pause

Überstunden

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -90,22 +90,12 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim if index == len(workDays)-1 { noBorder = "border-b-0" } - if day.Day.Weekday() == time.Monday { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

Wochenende

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } var templ_7745c5c3_Var5 = []any{noBorder} templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 39, Col: 56} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 36, Col: 56} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -140,7 +130,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, 10, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\">") 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, 12, "

") + 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(day.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: 59} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 40, Col: 59} } _, 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, 13, "

") + 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(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: 44, Col: 61} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 41, 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, 14, "

") + 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: 45, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 42, 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, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if (day.Absence != models.Absence{}) { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 45, Col: 64} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if (day.Absence != models.Absence{}) { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 48, Col: 64} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - 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, 18, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -230,7 +220,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, 19, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -238,7 +228,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, 20, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -246,6 +236,16 @@ 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, 19, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if day.Day.Weekday() == time.Friday { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

Wochenende

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } } templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
") if templ_7745c5c3_Err != nil { @@ -255,6 +255,484 @@ func PDFReportEmploye(e models.User, workDays []models.WorkDay, tsStart time.Tim }) } +func PDFReportEmployeTable(e models.User, workDays []models.WorkDay, 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var14 := templ.GetChildren(ctx) + if templ_7745c5c3_Var14 == nil { + templ_7745c5c3_Var14 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + + _, kw := tsStart.ISOWeek() + noBorder := "" + templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

Kim Mustermensch

Zeitraum: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(tsStart.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 69, Col: 52} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(tsEnd.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 69, Col: 98} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "

Arbeitszeit:

Überstunden:

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for index, day := range workDays { + + if index == len(workDays)-1 { + noBorder = "border-b-0" + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var18 = []any{noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var18...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + work, pause, overtime := day.GetAllWorkTimes(e) + templ_7745c5c3_Err = ColorDuration(work, noBorder).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ColorDuration(pause, noBorder).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ColorDuration(overtime, noBorder+" border-r-0").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if day.Day.Weekday() == time.Friday { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var17 string + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(kw) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 75, Col: 60} + } + _, 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, 25, "KommenGehenArbeitsartStundenPauseÜberstunden
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var20 string + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 90, Col: 58} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var21 = []any{"w-full border-collapse" + noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var21...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "") + 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, 32, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if (day.Absence != models.Absence{}) { + if len(day.Bookings) > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, 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: 95, Col: 85} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var24 string + templ_7745c5c3_Var24, 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: 96, Col: 87} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var25 string + templ_7745c5c3_Var25, 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: 97, Col: 65} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var26 string + templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 103, Col: 78} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var27 string + templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 108, Col: 78} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
Wochenende

Kim Mustermensch

Zeitraum: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var28 string + templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(tsStart.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 131, Col: 52} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, " - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var29 string + templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(tsEnd.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 131, Col: 98} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "

Arbeitszeit:

Überstunden:

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for index, day := range workDays { + + if index == len(workDays)-1 { + noBorder = "border-b-0" + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var31 = []any{noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var31...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + work, pause, overtime := day.GetAllWorkTimes(e) + templ_7745c5c3_Err = ColorDuration(work, noBorder).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ColorDuration(pause, noBorder).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ColorDuration(overtime, noBorder+" border-r-0").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if day.Day.Weekday() == time.Friday { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var30 string + templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(kw) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 137, Col: 60} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "KommenGehenArbeitsartStundenPauseÜberstunden
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var33 string + templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(day.Day.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 152, Col: 58} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var34 = []any{"w-full border-collapse" + noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var34...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "") + 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, 53, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if (day.Absence != models.Absence{}) { + if len(day.Bookings) > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var36 string + templ_7745c5c3_Var36, 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: 157, Col: 85} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var37 string + templ_7745c5c3_Var37, 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: 158, Col: 87} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var38 string + templ_7745c5c3_Var38, 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: 159, Col: 65} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var39 string + templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 165, Col: 78} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var40 string + templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(day.Absence.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 170, Col: 78} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "
Wochenende
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + func ColorDuration(d time.Duration, classes string) 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 @@ -271,9 +749,9 @@ func ColorDuration(d time.Duration, classes string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var14 := templ.GetChildren(ctx) - if templ_7745c5c3_Var14 == nil { - templ_7745c5c3_Var14 = templ.NopComponent + templ_7745c5c3_Var41 := templ.GetChildren(ctx) + if templ_7745c5c3_Var41 == nil { + templ_7745c5c3_Var41 = templ.NopComponent } ctx = templ.ClearChildren(ctx) @@ -281,38 +759,38 @@ func ColorDuration(d time.Duration, classes string) templ.Component { if d.Abs() < time.Minute { color = "text-neutral-300" } - var templ_7745c5c3_Var15 = []any{color + " " + classes} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var15...) + var templ_7745c5c3_Var42 = []any{color + " " + classes} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var42...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "\">") 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)) + var templ_7745c5c3_Var44 string + templ_7745c5c3_Var44, 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: 67, Col: 71} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 199, Col: 71} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/timeComponents.templ b/Backend/templates/timeComponents.templ index 81862f4..db79920 100644 --- a/Backend/templates/timeComponents.templ +++ b/Backend/templates/timeComponents.templ @@ -57,7 +57,7 @@ templ dayComponent(workDay models.WorkDay, submitted bool) { if (workDay.RequiresAction()) {

Bitte anpassen

} else { -

{ work }

+

{ work }

if pause != "" {

{ pause }

} diff --git a/Backend/templates/timeComponents_templ.go b/Backend/templates/timeComponents_templ.go index 47896fd..83fc257 100644 --- a/Backend/templates/timeComponents_templ.go +++ b/Backend/templates/timeComponents_templ.go @@ -205,14 +205,14 @@ func dayComponent(workDay models.WorkDay, submitted bool) templ.Component { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(work) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 60, Col: 35} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 60, Col: 149} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { -- 2.49.1