feat: change Manual time entry to work with hours instead of start and end time

according to add hours as well the logic was changed to accept ours for
manual entries instead of start and end time. This allows to add
negative numbers as well, which are added to working time.
This commit is contained in:
Patryk Hegenberg 2025-11-08 11:27:42 +01:00
parent c07019e3eb
commit 84def05c50
4 changed files with 84 additions and 135 deletions

View file

@ -307,12 +307,12 @@ func GetWeeklyHours(db *sql.DB) ([]WeeklyHours, error) {
year, week := t.ISOWeek()
var hours float64
if entryType == "lesson" {
hours = 1.0
} else {
hours = calculateHoursDiff(startTime, endTime)
entry := TimeEntry{
Type: entryType,
StartTime: startTime,
EndTime: endTime,
}
hours := calculateHours(entry)
key := fmt.Sprintf("%d_%d_%d", userID, year, week)
if existing, exists := hoursMap[key]; exists {
@ -359,57 +359,6 @@ func GetWeeklyHours(db *sql.DB) ([]WeeklyHours, error) {
return result, nil
}
// func GetYearlyHoursSummary(db *sql.DB) ([]WeeklyHours, error) {
// users, err := GetAllUsers(db)
// if err != nil {
// return nil, err
// }
// entries, err := GetAllTimeEntries(db)
// if err != nil {
// return nil, err
// }
// userTotals := make(map[int]float64)
// usernames := make(map[int]string)
// for _, entry := range entries {
// var hours float64
// if entry.Type == "lesson" {
// hours = 1.0
// } else {
// hours = calculateHoursDiff(entry.StartTime, entry.EndTime)
// }
// userTotals[entry.UserID] += hours
// usernames[entry.UserID] = entry.Username
// }
// var result []WeeklyHours
// for _, user := range users {
// if !user.IsAdmin {
// total := userTotals[user.ID]
// remaining := user.YearlyHours - total
// result = append(result, WeeklyHours{
// UserID: user.ID,
// Username: user.Username,
// Year: time.Now().Year(),
// Week: 0,
// TotalHours: total,
// YearlyTarget: user.YearlyHours,
// YearlyActual: total,
// RemainingYearly: remaining,
// })
// }
// }
// sort.Slice(result, func(i, j int) bool {
// return result[i].Username < result[j].Username
// })
// return result, nil
// }
func calculateHoursDiff(startTime, endTime string) float64 {
parseTime := func(timeStr string) float64 {
parts := strings.Split(timeStr, ":")
@ -471,7 +420,6 @@ func CheckUserHasEntriesForWeek(db *sql.DB, userID int, year int, week int) (boo
var count int
err := db.QueryRow(query, userID,
dateList[0], dateList[1], dateList[2], dateList[3], dateList[4]).Scan(&count)
if err != nil {
log.Printf("Error checking entries: %v", err)
return false, err
@ -489,7 +437,7 @@ func GetActiveSchoolYear(db *sql.DB) (*SchoolYear, error) {
`).Scan(&sy.ID, &sy.Name, &sy.StartDate, &sy.EndDate, &sy.IsActive, &sy.CreatedAt)
if err == sql.ErrNoRows {
return nil, nil // Kein aktives Schuljahr
return nil, nil
}
return &sy, err
}
@ -560,7 +508,6 @@ func GetYearlyHoursSummary(db *sql.DB) ([]WeeklyHours, error) {
WHERE date >= ? AND date <= ?
ORDER BY date DESC
`, schoolYear.StartDate, schoolYear.EndDate)
if err != nil {
return []WeeklyHours{}, err
}
@ -576,12 +523,12 @@ func GetYearlyHoursSummary(db *sql.DB) ([]WeeklyHours, error) {
continue
}
var hours float64
if entryType == "lesson" {
hours = 1.0
} else {
hours = calculateHoursDiff(startTime, endTime)
entry := TimeEntry{
Type: entryType,
StartTime: startTime,
EndTime: endTime,
}
hours := calculateHours(entry)
userTotals[userID] += hours
}
@ -606,3 +553,30 @@ func GetYearlyHoursSummary(db *sql.DB) ([]WeeklyHours, error) {
return result, nil
}
func CreateManualTimeEntry(db *sql.DB, entry *TimeEntry, hours float64) error {
entry.StartTime = fmt.Sprintf("%.2f", hours)
entry.EndTime = "manual"
entry.Type = "manual"
_, err := db.Exec(`
INSERT INTO time_entries (user_id, schedule_id, date, type, start_time, end_time)
VALUES (?, 0, ?, ?, ?, ?)
`, entry.UserID, entry.Date, entry.Type, entry.StartTime, entry.EndTime)
return err
}
func calculateHours(entry TimeEntry) float64 {
if entry.Type == "lesson" {
return 1.0
} else if entry.Type == "manual" {
hours, err := strconv.ParseFloat(entry.StartTime, 64)
if err != nil {
return 0
}
return hours
} else {
return calculateHoursDiff(entry.StartTime, entry.EndTime)
}
}

View file

@ -90,17 +90,15 @@ func (app *App) GetYearlyHoursSummaryHandler(c echo.Context) error {
func (app *App) AdminCreateTimeEntryHandler(c echo.Context) error {
isAdmin, _ := c.Get("is_admin").(bool)
if !isAdmin {
return echo.NewHTTPError(http.StatusForbidden, "Only admins can create entries for others")
}
var req struct {
UserID int `json:"user_id"`
Date string `json:"date"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
Type string `json:"type"`
UserID int `json:"user_id"`
Date string `json:"date"`
Hours float64 `json:"hours"`
Type string `json:"type"`
}
if err := c.Bind(&req); err != nil {
@ -110,16 +108,16 @@ func (app *App) AdminCreateTimeEntryHandler(c echo.Context) error {
entry := TimeEntry{
UserID: req.UserID,
Date: req.Date,
StartTime: req.StartTime,
EndTime: req.EndTime,
Type: req.Type,
StartTime: "00:00",
EndTime: "00:00",
Type: "manual",
}
if err := CreateTimeEntry(app.DB, &entry); err != nil {
if err := CreateManualTimeEntry(app.DB, &entry, req.Hours); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}
return c.JSON(http.StatusCreated, map[string]string{"message": "time entry created"})
return c.NoContent(http.StatusCreated)
}
func (app *App) GetUsersHandler(c echo.Context) error {

View file

@ -192,7 +192,6 @@ func (l *LoginRateLimiter) Middleware() echo.MiddlewareFunc {
func HTTPSRedirectMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Nur in Production aktivieren
if os.Getenv("ENVIRONMENT") == "production" {
if c.Request().Header.Get("X-Forwarded-Proto") != "https" {
return c.Redirect(http.StatusMovedPermanently,