Files
arbeitszeitmessung/Backend/models/workWeek.go

203 lines
5.4 KiB
Go

package models
import (
"database/sql"
"errors"
"log"
"sort"
"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))
sort.Slice(w.Days, func(i, j int) bool {
return w.Days[i].Date().Before(w.Days[j].Date())
})
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
}