From 7e27c944f328d7d3bbd5fe5c849eb146ee078fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Tr=C3=B6ger?= Date: Wed, 1 Oct 2025 21:56:18 +0200 Subject: [PATCH 1/3] updated time editing ui --- Backend/endpoints/team.go | 2 +- Backend/models/absence.go | 4 + Backend/models/workDay.go | 13 +- Backend/src/main.css | 25 ++ Backend/static/css/styles.css | 147 ++++------- Backend/static/script.js | 21 +- Backend/templates/timeComponents.templ | 53 ++-- Backend/templates/timeComponents_templ.go | 236 ++++++++++++++---- Backend/templates/timePage.templ | 16 +- Backend/templates/timePage_templ.go | 150 +++++------ DB/initdb/01_schema.sql | 6 +- Makefile | 4 +- migrations/20250916093608_kurzarbeit.down.sql | 2 - migrations/20250916093608_kurzarbeit.up.sql | 2 - 14 files changed, 392 insertions(+), 289 deletions(-) diff --git a/Backend/endpoints/team.go b/Backend/endpoints/team.go index e026488..397d45a 100644 --- a/Backend/endpoints/team.go +++ b/Backend/endpoints/team.go @@ -79,5 +79,5 @@ func showWeeks(w http.ResponseWriter, r *http.Request) { workWeeks = append(workWeeks, weeks...) } // isRunningWeek := time.Since(lastSub) < 24*5*time.Hour //the last submission is this week and cannot be send yet - templates.TeamPage([]models.WorkWeek{userWeek, userWeek}, userWeek).Render(r.Context(), w) + templates.TeamPage(workWeeks, userWeek).Render(r.Context(), w) } diff --git a/Backend/models/absence.go b/Backend/models/absence.go index 7d9e913..e3296a4 100644 --- a/Backend/models/absence.go +++ b/Backend/models/absence.go @@ -45,6 +45,10 @@ func (a *Absence) Date() time.Time { return a.Day.Truncate(24 * time.Hour) } +func (a *Absence) IsMultiDay() bool { + return !a.DateFrom.Equal(a.DateTo) +} + func (a *Absence) TimeWorkVirtual(u User) time.Duration { return a.TimeWorkReal(u) } diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index 5a99af4..cde6dd3 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -3,9 +3,9 @@ package models import ( "arbeitszeitmessung/helper" "encoding/json" + "fmt" "log" "sort" - "strconv" "time" ) @@ -87,8 +87,8 @@ func (d *WorkDay) TimeWorkVirtual(u User) time.Duration { return d.workTime } -func (d *WorkDay) GetKurzArbeit() Absence { - return d.kurzArbeitAbsence +func (d *WorkDay) GetKurzArbeit() *Absence { + return &d.kurzArbeitAbsence } func (d *WorkDay) TimeWorkReal(u User) time.Duration { @@ -144,7 +144,7 @@ func (d *WorkDay) TimePauseReal(u User) (work, pause time.Duration) { } func (d *WorkDay) ToString() string { - return "WorkDay" + return fmt.Sprintf("WorkDay: %s with %d bookings and worktime: %s", d.Date().Format("2006-01-02"), len(d.Bookings), helper.FormatDuration(d.workTime)) } func (d *WorkDay) IsWorkDay() bool { @@ -231,7 +231,7 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay { return workDays } defer rows.Close() - emptyDays, _ := strconv.ParseBool(helper.GetEnv("EMPTY_DAYS", "false")) + // emptyDays, _ := strconv.ParseBool(helper.GetEnv("EMPTY_DAYS", "false")) for rows.Next() { var workDay WorkDay var bookings []byte @@ -251,11 +251,12 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay { workDay.Bookings = []Booking{} } workDay.TimePauseReal(user) - if emptyDays && !helper.IsWeekend(workDay.Date()) { + if len(workDay.Bookings) > 1 || !helper.IsWeekend(workDay.Date()) { workDays = append(workDays, workDay) } } if err = rows.Err(); err != nil { + log.Println("Error in workday rows!", err) return workDays } return workDays diff --git a/Backend/src/main.css b/Backend/src/main.css index 9afdfb3..85052e2 100644 --- a/Backend/src/main.css +++ b/Backend/src/main.css @@ -110,6 +110,31 @@ color: var(--color-neutral-800); } + .edit-box { + border-radius: var(--radius-md); + overflow: hidden; + border-color: var(--color-neutral-500); + transition-property: background-color, border-color; + transition-timing-function: var(--default-transition-timing-function) * 2; + transition-duration: var(--default-transition-duration); + outline: none; + + &:is(:where(.group):is(.edit) *) { + border-width: 1px; + } + } + + .edit-box:hover { + &:is(:where(.group):is(.edit) *) { + background-color: var(--color-white); + border-color: var(--color-neutral-300); + } + } + + .edit-box input:focus { + outline: none; + } + @media (width >=48rem) { .grid-main { grid-template-columns: repeat(5, 1fr); diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css index 1e919bf..387452a 100644 --- a/Backend/static/css/styles.css +++ b/Backend/static/css/styles.css @@ -21,7 +21,6 @@ --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); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; @@ -198,14 +197,14 @@ .relative { position: relative; } - .top-2 { - top: calc(var(--spacing) * 2); - } .top-2\.5 { top: calc(var(--spacing) * 2.5); } - .right-2 { - right: calc(var(--spacing) * 2); + .top-\[0\.125rem\] { + top: 0.125rem; + } + .right-1 { + right: calc(var(--spacing) * 1); } .right-2\.5 { right: calc(var(--spacing) * 2.5); @@ -237,19 +236,6 @@ .ml-1 { margin-left: calc(var(--spacing) * 1); } - .icon-\[material-symbols-light--add-circle-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='M11.5 16.5h1v-4h4v-1h-4v-4h-1v4h-4v1h4zm.503 4.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"); - } .icon-\[material-symbols-light--check-circle-outline\] { display: inline-block; width: 1.25em; @@ -367,18 +353,6 @@ width: calc(var(--spacing) * 4); height: calc(var(--spacing) * 4); } - .size-5 { - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - } - .size-6 { - width: calc(var(--spacing) * 6); - height: calc(var(--spacing) * 6); - } - .size-7 { - width: calc(var(--spacing) * 7); - height: calc(var(--spacing) * 7); - } .h-2 { height: calc(var(--spacing) * 2); } @@ -406,9 +380,6 @@ .w-5 { width: calc(var(--spacing) * 5); } - .w-9 { - width: calc(var(--spacing) * 9); - } .w-9\/10 { width: calc(9/10 * 100%); } @@ -421,20 +392,14 @@ .w-full { width: 100%; } - .flex-shrink { - flex-shrink: 1; - } .flex-shrink-0 { flex-shrink: 0; } - .shrink { - flex-shrink: 1; - } .flex-grow { flex-grow: 1; } - .grow { - flex-grow: 1; + .grow-0 { + flex-grow: 0; } .grow-1 { flex-grow: 1; @@ -442,18 +407,9 @@ .basis-\[content\] { flex-basis: content; } - .basis-auto { - flex-basis: auto; - } - .border-collapse { - border-collapse: collapse; - } .cursor-pointer { cursor: pointer; } - .resize { - resize: both; - } .scroll-m-2 { scroll-margin: calc(var(--spacing) * 2); } @@ -551,10 +507,17 @@ .rounded-md { border-radius: var(--radius-md); } + .rounded-none { + border-radius: 0; + } .border { border-style: var(--tw-border-style); border-width: 1px; } + .border-0 { + border-style: var(--tw-border-style); + border-width: 0px; + } .border-r-0 { border-right-style: var(--tw-border-style); border-right-width: 0px; @@ -567,18 +530,19 @@ border-bottom-style: var(--tw-border-style); border-bottom-width: 0px; } - .border-neutral-200 { - border-color: var(--color-neutral-200); + .border-dashed { + --tw-border-style: dashed; + border-style: dashed; } .border-neutral-300 { border-color: var(--color-neutral-300); } + .border-neutral-500 { + border-color: var(--color-neutral-500); + } .border-neutral-600 { border-color: var(--color-neutral-600); } - .border-neutral-900 { - border-color: var(--color-neutral-900); - } .bg-accent { background-color: var(--color-accent); } @@ -600,9 +564,6 @@ .bg-red-600 { background-color: var(--color-red-600); } - .mask-repeat { - mask-repeat: repeat; - } .p-1 { padding: calc(var(--spacing) * 1); } @@ -646,6 +607,9 @@ .text-accent { color: var(--color-accent); } + .text-black { + color: var(--color-black); + } .text-neutral-300 { color: var(--color-neutral-300); } @@ -670,13 +634,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,); } @@ -720,6 +677,11 @@ } } } + .group-\[\.edit\]\:ml-2 { + &:is(:where(.group):is(.edit) *) { + margin-left: calc(var(--spacing) * 2); + } + } .group-\[\.edit\]\:block { &:is(:where(.group):is(.edit) *) { display: block; @@ -745,13 +707,6 @@ color: var(--color-neutral-400); } } - .hover\:border-neutral-300 { - &:hover { - @media (hover: hover) { - border-color: var(--color-neutral-300); - } - } - } .hover\:border-neutral-500 { &:hover { @media (hover: hover) { @@ -773,13 +728,6 @@ } } } - .hover\:bg-red-500 { - &:hover { - @media (hover: hover) { - background-color: var(--color-red-500); - } - } - } .hover\:bg-red-700 { &:hover { @media (hover: hover) { @@ -787,13 +735,6 @@ } } } - .hover\:text-accent { - &:hover { - @media (hover: hover) { - color: var(--color-accent); - } - } - } .hover\:text-white { &:hover { @media (hover: hover) { @@ -801,11 +742,6 @@ } } } - .focus\:border-neutral-400 { - &:focus { - border-color: var(--color-neutral-400); - } - } .focus\:bg-neutral-700 { &:focus { background-color: var(--color-neutral-700); @@ -1028,6 +964,27 @@ background-color: var(--color-neutral-100); color: var(--color-neutral-800); } + .edit-box { + border-radius: var(--radius-md); + overflow: hidden; + border-color: var(--color-neutral-500); + transition-property: background-color, border-color; + transition-timing-function: var(--default-transition-timing-function) * 2; + transition-duration: var(--default-transition-duration); + outline: none; + &:is(:where(.group):is(.edit) *) { + border-width: 1px; + } + } + .edit-box:hover { + &:is(:where(.group):is(.edit) *) { + background-color: var(--color-white); + border-color: var(--color-neutral-300); + } + } + .edit-box input:focus { + outline: none; + } @media (width >=48rem) { .grid-main { grid-template-columns: repeat(5, 1fr); @@ -1060,11 +1017,6 @@ syntax: "*"; inherits: false; } -@property --tw-outline-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} @property --tw-blur { syntax: "*"; inherits: false; @@ -1129,7 +1081,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/static/script.js b/Backend/static/script.js index e5f27bd..04bae89 100644 --- a/Backend/static/script.js +++ b/Backend/static/script.js @@ -12,21 +12,22 @@ function editDay(element, event, formId) { } } +function syncFields(from, to, fieldsToSync) { + fieldsToSync.forEach((name) => { + const src = from.querySelector(`[name=${name}]`); + const target = to.querySelector(`[name=${name}]`); + if (!src || !target) return; + target.value = src.value; + }); +} + function editAbsence(element, event, absenceId) { + event.preventDefault(); var form = document.getElementById("absence_form"); - console.log(absenceId); if (absenceId != 0) { - const fieldsToSync = ["date_from", "date_to", "aw_type", "aw_id"]; - var dataForm = document.getElementById(absenceId); - - fieldsToSync.forEach((name) => { - const src = dataForm.querySelector(`[name=${name}]`); - const target = form.querySelector(`[name=${name}]`); - if (!src || !target) return; - target.value = src.value; - }); + syncFields(dataForm, form, ["date_from", "date_to", "aw_type", "aw_id"]); } else { var dataForm = element.closest(".grid-sub").querySelector(".all-booking-component > form"); form.querySelector("[name=date_from]").value = dataForm.id.replace("time-", ""); diff --git a/Backend/templates/timeComponents.templ b/Backend/templates/timeComponents.templ index f50e3a3..413c16b 100644 --- a/Backend/templates/timeComponents.templ +++ b/Backend/templates/timeComponents.templ @@ -124,31 +124,56 @@ templ timeGaugeComponent(progress int8, today bool) { } templ newAbsenceComponent() { - } +templ absenceComponent(a *models.Absence, isKurzarbeit bool) { +
+ + + + +

+ { a.AbwesenheitTyp.Name } + if a.IsMultiDay() { + bis { a.DateTo.Format("02.01.2006") } + } +

+
+ if isKurzarbeit { + + } +
+} + templ newBookingComponent(d *models.WorkDay) { -
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -393,64 +533,64 @@ func bookingComponent(booking models.Booking) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var15 := templ.GetChildren(ctx) - if templ_7745c5c3_Var15 == nil { - templ_7745c5c3_Var15 = templ.NopComponent + templ_7745c5c3_Var23 := templ.GetChildren(ctx) + if templ_7745c5c3_Var23 == nil { + templ_7745c5c3_Var23 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(booking.Timestamp.Format("15:04")) + var templ_7745c5c3_Var24 string + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(booking.Timestamp.Format("15:04")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 150, Col: 97} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 175, Col: 91} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + _, 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, 21, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "\" class=\"text-neutral-700 group-[.edit]:inline hidden bg-neutral-100 text-sm px-3 py-2 cursor-pointer\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var19 string - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(booking.GetBookingType()) + var templ_7745c5c3_Var27 string + templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(booking.GetBookingType()) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 152, Col: 29} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 177, Col: 29} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + _, 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, 24, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -474,12 +614,12 @@ func LegendComponent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var20 := templ.GetChildren(ctx) - if templ_7745c5c3_Var20 == nil { - templ_7745c5c3_Var20 = templ.NopComponent + templ_7745c5c3_Var28 := templ.GetChildren(ctx) + if templ_7745c5c3_Var28 == nil { + templ_7745c5c3_Var28 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
Fehler
Arbeitszeit unter regulär
Arbeitszeit vollständig
Überstunden
Keine Buchungen
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
Fehler
Arbeitszeit unter regulär
Arbeitszeit vollständig
Überstunden
Keine Buchungen
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/timePage.templ b/Backend/templates/timePage.templ index 323388d..5a7da26 100644 --- a/Backend/templates/timePage.templ +++ b/Backend/templates/timePage.templ @@ -98,9 +98,7 @@ templ defaultDayComponent(day models.IWorkDay) { @timeGaugeComponent(day.GetDayProgress(user), day.Date().Equal(time.Now().Truncate(24*time.Hour)))

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

if day.IsWorkDay() { {{ @@ -129,7 +127,7 @@ templ defaultDayComponent(day models.IWorkDay) {
@lineComponent() -
+ @newAbsenceComponent() if day.IsWorkDay() { {{ @@ -138,20 +136,18 @@ templ defaultDayComponent(day models.IWorkDay) { if len(workDay.Bookings) < 1 {

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

} + if workDay.IsKurzArbeit() { + @absenceComponent(workDay.GetKurzArbeit(), true) + } for _, booking := range workDay.Bookings { @bookingComponent(booking) } @newBookingComponent(workDay) - if workDay.IsKurzArbeit() { - @absentInput(workDay.GetKurzArbeit()) -

Kurzarbeit

- } } else { {{ absentDay, _ := day.(*models.Absence) }} - @absentInput(*absentDay) -

{ absentDay.AbwesenheitTyp.Name } bis { absentDay.DateTo.Format("02.01.2006") }

+ @absenceComponent(absentDay, false) }
diff --git a/Backend/templates/timePage_templ.go b/Backend/templates/timePage_templ.go index 4582490..17b528e 100644 --- a/Backend/templates/timePage_templ.go +++ b/Backend/templates/timePage_templ.go @@ -282,11 +282,9 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(day.Date().Format( - - "02.01.2006")) + templ_7745c5c3_Var13, 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/timePage.templ`, Line: 103, Col: 13} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 101, Col: 126} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { @@ -314,7 +312,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(work)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 115, Col: 155} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 113, Col: 155} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { @@ -337,7 +335,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var15 string templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(pause)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 118, Col: 173} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 116, Col: 173} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { @@ -360,7 +358,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var16 string templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(overtime)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 123, Col: 41} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 121, Col: 41} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) if templ_7745c5c3_Err != nil { @@ -381,7 +379,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var17 = []any{"flex flex-col gap-2 group w-full ", justify} + var templ_7745c5c3_Var17 = []any{"flex flex-col gap-2 group w-full", justify} templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err @@ -393,7 +391,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { var templ_7745c5c3_Var18 string templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs("time-" + day.Date().Format("2006-01-02")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 132, Col: 55} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 130, Col: 55} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { @@ -429,13 +427,23 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { return templ_7745c5c3_Err } } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if workDay.IsKurzArbeit() { + templ_7745c5c3_Err = absenceComponent(workDay.GetKurzArbeit(), true).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } for _, booking := range workDay.Bookings { templ_7745c5c3_Err = bookingComponent(booking).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -443,59 +451,15 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { 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 - } - if workDay.IsKurzArbeit() { - templ_7745c5c3_Err = absentInput(workDay.GetKurzArbeit()).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "

Kurzarbeit

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } } else { absentDay, _ := day.(*models.Absence) - templ_7745c5c3_Err = absentInput(*absentDay).Render(ctx, templ_7745c5c3_Buffer) - 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_Var20 string - templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(absentDay.AbwesenheitTyp.Name) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 154, Col: 39} - } - _, 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, 38, " bis ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(absentDay.DateTo.Format("02.01.2006")) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 154, Col: 116} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "

") + templ_7745c5c3_Err = absenceComponent(absentDay, false).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -503,7 +467,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -527,64 +491,64 @@ func absentInput(a models.Absence) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var22 := templ.GetChildren(ctx) - if templ_7745c5c3_Var22 == nil { - templ_7745c5c3_Var22 = templ.NopComponent + templ_7745c5c3_Var20 := templ.GetChildren(ctx) + if templ_7745c5c3_Var20 == nil { + templ_7745c5c3_Var20 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/DB/initdb/01_schema.sql b/DB/initdb/01_schema.sql index 56b52d9..e3e795f 100644 --- a/DB/initdb/01_schema.sql +++ b/DB/initdb/01_schema.sql @@ -40,11 +40,11 @@ CREATE TABLE "s_personal_daten" ( "geschlecht" int2, "card_uid" varchar(255), "hauptbeschaeftigungs_ort" int2, - "arbeitszeit_per_tag" float4 NOT NULL, - "arbeitszeit_per_woche" float4 NOT NULL, + "arbeitszeit_per_tag" float4, + "arbeitszeit_per_woche" float4, "arbeitszeit_min_start" time(6), "arbeitszeit_max_ende" time(6), - "vorgesetzter_pers_nr" int4 NOT NULL + "vorgesetzter_pers_nr" int4 ); COMMENT ON COLUMN "s_personal_daten"."geschlecht" IS '1==weiblich, 2==maennlich, 3==divers'; diff --git a/Makefile b/Makefile index 994d36c..283ab33 100644 --- a/Makefile +++ b/Makefile @@ -44,8 +44,8 @@ generateFrontend: backend: generateFrontend login_registry - docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:latest Backend --push - docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:${GIT_COMMIT} Backend --push + docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:latest Backend --load #--push + # docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:${GIT_COMMIT} Backend //--push test: $(MAKE) -C Backend test diff --git a/migrations/20250916093608_kurzarbeit.down.sql b/migrations/20250916093608_kurzarbeit.down.sql index 697259f..c3e5291 100644 --- a/migrations/20250916093608_kurzarbeit.down.sql +++ b/migrations/20250916093608_kurzarbeit.down.sql @@ -1,8 +1,6 @@ -- reverse: modify "wochen_report" table ALTER TABLE "wochen_report" ALTER COLUMN "personal_nummer" DROP NOT NULL; -- reverse: modify "s_personal_daten" table -ALTER TABLE "s_personal_daten" ALTER COLUMN "arbeitszeit_per_woche" DROP NOT NULL, ALTER COLUMN "vorgesetzter_pers_nr" DROP NOT NULL, ALTER COLUMN "arbeitszeit_per_tag" DROP NOT NULL; --- reverse: modify "s_anwesenheit_typen" table ALTER TABLE "s_anwesenheit_typen" ALTER COLUMN "anwesenheit_name" DROP NOT NULL; -- reverse: set comment to column: "arbeitszeit_equivalent" on table: "s_abwesenheit_typen" COMMENT ON COLUMN "s_abwesenheit_typen"."arbeitszeit_equivalent" IS NULL; diff --git a/migrations/20250916093608_kurzarbeit.up.sql b/migrations/20250916093608_kurzarbeit.up.sql index b944343..beb69ae 100644 --- a/migrations/20250916093608_kurzarbeit.up.sql +++ b/migrations/20250916093608_kurzarbeit.up.sql @@ -8,6 +8,4 @@ COMMENT ON COLUMN "s_abwesenheit_typen"."arbeitszeit_equivalent" IS '0=keine Arb -- modify "s_anwesenheit_typen" table ALTER TABLE "s_anwesenheit_typen" ALTER COLUMN "anwesenheit_name" SET NOT NULL; -- modify "s_personal_daten" table -ALTER TABLE "s_personal_daten" ALTER COLUMN "arbeitszeit_per_tag" SET NOT NULL, ALTER COLUMN "vorgesetzter_pers_nr" SET NOT NULL, ALTER COLUMN "arbeitszeit_per_woche" SET NOT NULL; --- modify "wochen_report" table ALTER TABLE "wochen_report" ALTER COLUMN "personal_nummer" SET NOT NULL; From 3dd4b134c85dd6fbc18adb8dec85d046d674658e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Tr=C3=B6ger?= Date: Wed, 1 Oct 2025 22:53:27 +0200 Subject: [PATCH 2/3] closes #44 --- Backend/endpoints/team_presence.go | 5 +- Backend/helper/types.go | 20 +++++++- Backend/models/user.go | 2 +- Backend/src/main.css | 2 +- Backend/static/css/styles.css | 2 +- Backend/templates/pages.templ | 39 +++++++++----- Backend/templates/pages_templ.go | 80 +++++++++++++++++++++-------- Backend/templates/timePage.templ | 2 +- Backend/templates/timePage_templ.go | 2 +- 9 files changed, 110 insertions(+), 44 deletions(-) diff --git a/Backend/endpoints/team_presence.go b/Backend/endpoints/team_presence.go index e4ea775..414f8b6 100644 --- a/Backend/endpoints/team_presence.go +++ b/Backend/endpoints/team_presence.go @@ -28,10 +28,9 @@ func teamPresence(w http.ResponseWriter, r *http.Request) { log.Println("Error getting user!", err) } team, err := user.GetTeamMembers() - teamPresence := make(map[bool][]models.User) + teamPresence := make(map[models.User]bool) for _, user := range team { - present := user.CheckAnwesenheit() - teamPresence[present] = append(teamPresence[present], user) + teamPresence[user] = user.CheckAnwesenheit() } if err != nil { diff --git a/Backend/helper/types.go b/Backend/helper/types.go index 84fa2c5..7dd6cce 100644 --- a/Backend/helper/types.go +++ b/Backend/helper/types.go @@ -3,7 +3,23 @@ package helper import "time" type TimeFormValue struct { - TsFrom time.Time - TsTo time.Time + TsFrom time.Time + TsTo time.Time CardUID string } + +func BoolToInt(b bool) int { + var i int = 0 + if b { + i = 1 + } + return i +} + +func BoolToInt8(b bool) int8 { + var i int8 = 0 + if b { + i = 1 + } + return i +} diff --git a/Backend/models/user.go b/Backend/models/user.go index ccb188a..e3d94a9 100644 --- a/Backend/models/user.go +++ b/Backend/models/user.go @@ -173,7 +173,7 @@ func (u *User) ChangePass(password, newPassword string) (bool, error) { func (u *User) GetTeamMembers() ([]User, error) { var teamMembers []User - qStr, err := DB.Prepare(`SELECT personal_nummer FROM s_personal_daten WHERE vorgesetzter_pers_nr = $1`) + qStr, err := DB.Prepare(`SELECT personal_nummer FROM s_personal_daten WHERE vorgesetzter_pers_nr = $1 ORDER BY "nachname";`) if err != nil { return teamMembers, err } diff --git a/Backend/src/main.css b/Backend/src/main.css index 85052e2..c54539c 100644 --- a/Backend/src/main.css +++ b/Backend/src/main.css @@ -41,7 +41,7 @@ @layer components { .grid-main { display: grid; - grid-template-columns: 4fr 6fr 1fr; + grid-template-columns: 4fr 3fr 3fr 1fr; align-items: stretch; } diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css index 387452a..9f5c58c 100644 --- a/Backend/static/css/styles.css +++ b/Backend/static/css/styles.css @@ -909,7 +909,7 @@ @layer components { .grid-main { display: grid; - grid-template-columns: 4fr 6fr 1fr; + grid-template-columns: 4fr 3fr 3fr 1fr; align-items: stretch; } .grid-sub { diff --git a/Backend/templates/pages.templ b/Backend/templates/pages.templ index 8ca8aff..3c60778 100644 --- a/Backend/templates/pages.templ +++ b/Backend/templates/pages.templ @@ -1,6 +1,7 @@ package templates import "arbeitszeitmessung/models" +import "arbeitszeitmessung/helper" templ Base() { @@ -147,26 +148,36 @@ templ TeamPage(weeks []models.WorkWeek, userWeek models.WorkWeek) { } -templ TeamPresencePage(teamPresence map[bool][]models.User) { +templ TeamPresencePage(teamPresence map[models.User]bool) { @Base() @headerComponent()
-

Anwesend

-
- for _, user := range teamPresence[true] { - @userPresenceComponent(user, true) - } -
+

Mitarbeiter

-
-

Nicht Anwesend

-
- for _, user := range teamPresence[false] { - @userPresenceComponent(user, false) - } + for user, present := range teamPresence { +
+
+ @timeGaugeComponent(helper.BoolToInt8(present)*100-1, false) +

{ user.Vorname } { user.Name }

+
+
+ if present { + Anwesend + } else { + Abwesend + } +
-
+ } + //
+ //

Nicht Anwesend

+ //
+ // for _, user := range teamPresence[false] { + // @userPresenceComponent(user, false) + // } + //
+ //
} diff --git a/Backend/templates/pages_templ.go b/Backend/templates/pages_templ.go index 3a54c9b..04f8e10 100644 --- a/Backend/templates/pages_templ.go +++ b/Backend/templates/pages_templ.go @@ -9,6 +9,7 @@ import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" import "arbeitszeitmessung/models" +import "arbeitszeitmessung/helper" func Base() templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { @@ -76,7 +77,7 @@ func LoginPage(success bool, errorMsg string) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(errorMsg) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 24, Col: 46} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 25, Col: 46} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -246,7 +247,7 @@ func TeamPage(weeks []models.WorkWeek, userWeek models.WorkWeek) templ.Component }) } -func TeamPresencePage(teamPresence map[bool][]models.User) templ.Component { +func TeamPresencePage(teamPresence map[models.User]bool) 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 { @@ -275,27 +276,66 @@ func TeamPresencePage(teamPresence map[bool][]models.User) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

Anwesend

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

Mitarbeiter

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - for _, user := range teamPresence[true] { - templ_7745c5c3_Err = userPresenceComponent(user, true).Render(ctx, templ_7745c5c3_Buffer) + for user, present := range teamPresence { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = timeGaugeComponent(helper.BoolToInt8(present)*100-1, false).Render(ctx, templ_7745c5c3_Buffer) + 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 + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(user.Vorname) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 162, Col: 22} + } + _, 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, 19, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(user.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 162, Col: 36} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + 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 + } + if present { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "Anwesend") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "Abwesend") + 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 } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

Nicht Anwesend

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, user := range teamPresence[false] { - templ_7745c5c3_Err = userPresenceComponent(user, false).Render(ctx, templ_7745c5c3_Buffer) - 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, 24, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -319,12 +359,12 @@ func LogoutButton() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var8 := templ.GetChildren(ctx) - if templ_7745c5c3_Var8 == nil { - templ_7745c5c3_Var8 = templ.NopComponent + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/timePage.templ b/Backend/templates/timePage.templ index 5a7da26..eb297d6 100644 --- a/Backend/templates/timePage.templ +++ b/Backend/templates/timePage.templ @@ -125,7 +125,7 @@ templ defaultDayComponent(day models.IWorkDay) { }
-
+
@lineComponent()
@newAbsenceComponent() diff --git a/Backend/templates/timePage_templ.go b/Backend/templates/timePage_templ.go index 17b528e..55a713c 100644 --- a/Backend/templates/timePage_templ.go +++ b/Backend/templates/timePage_templ.go @@ -371,7 +371,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component { } } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } From c093127a8cf61ff1d64e3cdd8ff1f26eb8137d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Tr=C3=B6ger?= Date: Wed, 1 Oct 2025 23:02:57 +0200 Subject: [PATCH 3/3] added worktime + overtime to pdf --- Backend/endpoints/pdf.go | 7 +- Backend/templates/pdf.templ | 8 +- Backend/templates/pdf_templ.go | 190 +++++++++++++++++++++------------ 3 files changed, 131 insertions(+), 74 deletions(-) diff --git a/Backend/endpoints/pdf.go b/Backend/endpoints/pdf.go index ce27116..87beb06 100644 --- a/Backend/endpoints/pdf.go +++ b/Backend/endpoints/pdf.go @@ -30,7 +30,12 @@ func PDFHandler(w http.ResponseWriter, r *http.Request) { //TODO: only accepted weeks weeks := models.GetDays(user, startDate, endDate, false) + var aggregatedOvertime, aggregatedWorkTime time.Duration + for _, day := range weeks { + aggregatedOvertime += day.TimeOvertimeReal(user) + aggregatedWorkTime += day.TimeWorkVirtual(user) + } // log.Printf("Using Dates: %s - %s\n", startDate.String(), endDate.String()) - templates.PDFReportEmploye(user, weeks, startDate, endDate).Render(r.Context(), w) + templates.PDFReportEmploye(user, aggregatedOvertime, aggregatedWorkTime, weeks, startDate, endDate).Render(r.Context(), w) } diff --git a/Backend/templates/pdf.templ b/Backend/templates/pdf.templ index 2b92d10..204e9dd 100644 --- a/Backend/templates/pdf.templ +++ b/Backend/templates/pdf.templ @@ -6,7 +6,7 @@ import ( "time" ) -templ PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Time, tsEnd time.Time) { +templ PDFReportEmploye(e models.User, overtime, worktime time.Duration, workDays []models.IWorkDay, tsStart time.Time, tsEnd time.Time) { {{ _, kw := tsStart.ISOWeek() noBorder := "" @@ -14,10 +14,10 @@ templ PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.T @Base()
-

Kim Mustermensch

+

{ e.Vorname } { e.Name }

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

-

Arbeitszeit:

-

Überstunden:

+

Arbeitszeit: { helper.FormatDuration(worktime) }

+

Überstunden: { helper.FormatDuration(overtime) }

{ kw }

diff --git a/Backend/templates/pdf_templ.go b/Backend/templates/pdf_templ.go index d9c5e51..3c73ded 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.IWorkDay, tsStart time.Time, tsEnd time.Time) templ.Component { +func PDFReportEmploye(e models.User, overtime, worktime time.Duration, 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 { @@ -42,46 +42,98 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti 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, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var2 string - templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(tsStart.Format("02.01.2006")) + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(e.Vorname) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 18, Col: 52} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 17, Col: 45} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " - ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var3 string - templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(tsEnd.Format("02.01.2006")) + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(e.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 18, Col: 98} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 17, Col: 56} } _, 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, "

Zeitraum: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(kw) + templ_7745c5c3_Var4, 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: 23, 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_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, " - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, 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: 18, Col: 98} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

Arbeitszeit: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(worktime)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 19, Col: 58} + } + _, 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, 6, "

Überstunden: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(overtime)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pdf.templ`, Line: 20, Col: 59} + } + _, 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, 7, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, 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: 52} + } + _, 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, 8, "

Kommen

Gehen

Arbeitsart

Stunden

Pause

Überstunden

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -90,60 +142,60 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti if index == len(workDays)-1 { noBorder = "border-b-0" } - var templ_7745c5c3_Var5 = []any{noBorder} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) + var templ_7745c5c3_Var9 = []any{noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(day.Date().Format("02.01.2006")) + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, 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: 59} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + _, 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, 7, "

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

") 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...) + var templ_7745c5c3_Var12 = []any{"grid grid-cols-subgrid col-span-3 " + noBorder} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -151,56 +203,56 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti workDay, _ := day.(*models.WorkDay) for bookingI := 0; bookingI < len(workDay.Bookings); bookingI += 2 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") + 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(workDay.Bookings[bookingI].Timestamp.Format("15:04")) + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, 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)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

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

") 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")) + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, 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)) + _, 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, 12, "

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

") 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) + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, 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)) + _, 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, 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 } if workDay.IsKurzArbeit() { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "

Kurzarbeit

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

Kurzarbeit

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -208,25 +260,25 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti } else { absentDay, _ := day.(*models.Absence) - 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 } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(absentDay.AbwesenheitTyp.Name) + var templ_7745c5c3_Var17 string + templ_7745c5c3_Var17, 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)) + _, 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, 17, "

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

") 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, 22, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -235,7 +287,7 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti 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 } @@ -243,7 +295,7 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti 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, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -251,18 +303,18 @@ func PDFReportEmploye(e models.User, workDays []models.IWorkDay, tsStart time.Ti if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if day.Date().Weekday() == time.Friday { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

Wochenende

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

Wochenende

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -286,9 +338,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_Var18 := templ.GetChildren(ctx) + if templ_7745c5c3_Var18 == nil { + templ_7745c5c3_Var18 = templ.NopComponent } ctx = templ.ClearChildren(ctx) @@ -296,38 +348,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_Var19 = []any{color + " " + classes} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var19...) 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, 29, "\">") 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_Var21 string + templ_7745c5c3_Var21, 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)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }