package models import ( "database/sql" "errors" "log" "time" ) // Workweeks are type WorkWeek struct { Id int WorkDays []WorkDay Absences []Absence Days []IWorkDay User User WeekStart time.Time Worktime time.Duration Overtime time.Duration Status WeekStatus overtimeDiff time.Duration worktimeDiff time.Duration } type WeekStatus int8 const ( WeekStatusNone WeekStatus = iota WeekStatusSent WeekStatusAccepted WeekStatusDifferences ) func NewWorkWeek(user User, tsMonday time.Time, populate bool) WorkWeek { var week WorkWeek = WorkWeek{ User: user, WeekStart: tsMonday, Status: WeekStatusNone, } if populate { week.PopulateWithDays(0, 0) } return week } func (w *WorkWeek) PopulateWithDays(worktime time.Duration, overtime time.Duration) { w.Days = GetDays(w.User, w.WeekStart, w.WeekStart.Add(6*24*time.Hour), false) for _, day := range w.Days { w.Worktime += day.TimeWorkVirtual(w.User) } w.Overtime = w.Worktime - w.User.ArbeitszeitProWoche() w.Worktime = w.Worktime.Round(time.Minute) w.Overtime = w.Overtime.Round(time.Minute) if overtime == 0 && worktime == 0 { return } if overtime != w.Overtime || worktime != w.Worktime { w.Status = WeekStatusDifferences w.overtimeDiff = overtime w.worktimeDiff = worktime } } 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) aggregateWorkTime() time.Duration { var workTime time.Duration for _, day := range w.WorkDays { workTime += day.workTime } // 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 } func (w *WorkWeek) GetSendWeeks(user User) []WorkWeek { var weeks []WorkWeek qStr, err := DB.Prepare(`SELECT id, woche_start::DATE, (EXTRACT(epoch FROM arbeitszeit)*1000000000)::BIGINT, (EXTRACT(epoch FROM ueberstunden)*1000000000)::BIGINT 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 = WorkWeek{User: user} if err := rows.Scan(&week.Id, &week.WeekStart, &week.Worktime, &week.Overtime); err != nil { log.Println("Error scanning row!", err) return weeks } week.PopulateWithDays(week.Worktime, week.Overtime) weeks = append(weeks, week) } if err = rows.Err(); err != nil { return weeks } return weeks } var ErrRunningWeek = errors.New("Week is in running week") // creates a new entry in the woche_report table with the given workweek func (w *WorkWeek) SendWeek() 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, arbeitszeit = make_interval(secs => $3::numeric / 1000000000), ueberstunden = make_interval(secs => $4::numeric / 1000000000) 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, arbeitszeit, ueberstunden) VALUES ($1, $2, make_interval(secs => $3::numeric / 1000000000), make_interval(secs => $4::numeric / 1000000000));`) if err != nil { log.Println("Error preparing SQL statement", err) return err } } _, err = qStr.Exec(w.User.PersonalNummer, w.WeekStart, int64(w.Worktime), int64(w.Overtime)) 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 } func (w *WorkWeek) RequiresAction() bool { var requiresAction bool = false for _, day := range w.Days { requiresAction = requiresAction || day.RequiresAction() } return requiresAction }