package models import ( "arbeitszeitmessung/helper" "database/sql" "errors" "log" "time" ) // Workweeks are type WorkWeek struct { Id int WorkDays []WorkDay Absences []Absence User User WeekStart time.Time WorkHours time.Duration Status WeekStatus } type WeekStatus int8 const ( WeekStatusNone WeekStatus = iota WeekStatusSent WeekStatusAccepted ) func NewWorkWeek(user User, tsMonday time.Time, populate bool) WorkWeek { var week WorkWeek = WorkWeek{ User: user, WeekStart: tsMonday, Status: WeekStatusNone, } if populate { week.WorkDays = (*WorkDay).GetWorkDays(nil, user.CardUID, tsMonday, tsMonday.Add(7*24*time.Hour)) if absences, err := GetAbsenceByCardUID(user.CardUID, tsMonday, tsMonday.Add(7*24*time.Hour)); err == nil { week.Absences = absences } else { log.Printf("Error populating absences in workWeek (%s): %v", tsMonday, err) } week.WorkHours = week.aggregateWorkTime() } return week } func (w *WorkWeek) CheckStatus() WeekStatus { if w.Status != WeekStatusNone { return w.Status } if DB == nil { log.Println("Cannot access Database!") return w.Status } qStr, err := DB.Prepare(`SELECT bestaetigt FROM wochen_report WHERE woche_start = $1::DATE AND personal_nummer = $2;`) if err != nil { log.Println("Error preparing SQL statement", err) return w.Status } defer qStr.Close() var beastatigt bool err = qStr.QueryRow(w.WeekStart, w.User.PersonalNummer).Scan(&beastatigt) if err == sql.ErrNoRows { return w.Status } if err != nil { log.Println("Error querying database", err) return w.Status } if beastatigt { w.Status = WeekStatusAccepted } else { w.Status = WeekStatusSent } return w.Status } func (w *WorkWeek) GetWorkHourString() string { return helper.FormatDuration(w.WorkHours) } func (w *WorkWeek) aggregateWorkTime() time.Duration { var workTime 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) } return workTime } func (w *WorkWeek) GetSendWeeks(user User) []WorkWeek { var weeks []WorkWeek qStr, err := DB.Prepare(`SELECT id, woche_start::DATE FROM wochen_report WHERE bestaetigt = FALSE AND personal_nummer = $1;`) if err != nil { log.Println("Error preparing SQL statement", err) return weeks } defer qStr.Close() rows, err := qStr.Query(user.PersonalNummer) if err != nil { log.Println("Error querining db!", err) return weeks } defer rows.Close() for rows.Next() { var week WorkWeek week.User = user if err := rows.Scan(&week.Id, &week.WeekStart); err != nil { log.Println("Error scanning row!", err) return weeks } week.WorkDays = (*WorkDay).GetWorkDays(nil, user.CardUID, week.WeekStart, week.WeekStart.Add(7*24*time.Hour)) week.WorkHours = week.aggregateWorkTime() weeks = append(weeks, week) } if err = rows.Err(); err != nil { return weeks } return weeks } var ErrRunningWeek = errors.New("Week is in running week") func (w *WorkWeek) GetOvertime() time.Duration { var weekOvertime time.Duration = w.WorkHours - time.Duration(w.User.ArbeitszeitPerWoche*float32(time.Hour)).Round(time.Minute) return weekOvertime } // creates a new entry in the woche_report table with the given workweek func (w *WorkWeek) Send() error { var qStr *sql.Stmt var err error if time.Since(w.WeekStart) < 5*24*time.Hour { log.Println("Cannot send week, because it's the running week!") return ErrRunningWeek } if w.CheckStatus() != WeekStatusNone { qStr, err = DB.Prepare(`UPDATE "wochen_report" SET bestaetigt = FALSE, ueberstunden = $3 WHERE personal_nummer = $1 AND woche_start = $2;`) if err != nil { log.Println("Error preparing SQL statement", err) return err } } else { qStr, err = DB.Prepare(`INSERT INTO wochen_report (personal_nummer, woche_start, ueberstunden) VALUES ($1, $2, $3);`) if err != nil { log.Println("Error preparing SQL statement", err) return err } } _, err = qStr.Exec(w.User.PersonalNummer, w.WeekStart, w.GetOvertime().Hours()) if err != nil { log.Println("Error executing query!", err) return err } return nil } func (w *WorkWeek) Accept() error { qStr, err := DB.Prepare(`UPDATE "wochen_report" SET bestaetigt = TRUE WHERE personal_nummer = $1 AND woche_start = $2;`) if err != nil { log.Println("Error preparing SQL statement", err) return err } _, err = qStr.Exec(w.User.PersonalNummer, w.WeekStart) if err != nil { log.Println("Error executing query!", err) return err } return nil }