Files
arbeitszeitmessung/Backend/models/absence.go
Tom Tröger 90193e9346
All checks were successful
Tests / Run Go Tests (push) Successful in 37s
closes #38, #39, #40
2025-09-28 23:29:28 +02:00

265 lines
6.8 KiB
Go

package models
import (
"encoding/json"
"errors"
"log"
"time"
)
type AbsenceType struct {
Id int8 `json:"abwesenheit_id"`
Name string `json:"abwesenheit_name"`
WorkTime int8 `json:"arbeitszeit_equivalent"`
}
type Absence struct {
Day time.Time
CounterId int
CardUID string
AbwesenheitTyp AbsenceType
DateFrom time.Time
DateTo time.Time
}
func NewAbsence(card_uid string, abwesenheit_typ int, datum time.Time) (Absence, error) {
if abwesenheit_typ < 0 {
return Absence{
CardUID: card_uid,
AbwesenheitTyp: AbsenceType{0, "Custom absence", 100},
DateFrom: datum,
}, nil
}
_absenceType, ok := GetAbsenceTypesCached()[int8(abwesenheit_typ)]
if !ok {
return Absence{}, errors.New("Invalid absencetype")
}
return Absence{
CardUID: card_uid,
AbwesenheitTyp: _absenceType,
DateFrom: datum,
}, nil
}
func (a *Absence) Date() time.Time {
return a.Day.Truncate(24 * time.Hour)
}
func (a *Absence) TimeWorkVirtual(u User) time.Duration {
return a.TimeWorkReal(u)
}
func (a *Absence) TimeWorkReal(u User) time.Duration {
if a.AbwesenheitTyp.WorkTime > 1 {
return time.Duration(u.ArbeitszeitPerTag * float32(time.Hour)).Round(time.Minute)
}
return 0
}
func (a *Absence) TimePauseReal(u User) (work, pause time.Duration) {
return 0, 0
}
func (a *Absence) TimeOvertimeReal(u User) time.Duration {
if a.AbwesenheitTyp.WorkTime > 1 {
return 0
}
return -u.ArbeitszeitProTag()
}
func (a *Absence) ToString() string {
return "Abwesenheit"
}
func (a *Absence) IsWorkDay() bool {
return false
}
func (a *Absence) IsKurzArbeit() bool {
return false
}
func (a *Absence) GetDayProgress(u User) int8 {
return 100
}
func (a *Absence) RequiresAction() bool {
return false
}
func (a *Absence) GetAllWorkTimesVirtual(u User) (work, pause, overtime time.Duration) {
if a.AbwesenheitTyp.WorkTime > 1 {
return u.ArbeitszeitProTag(), 0, 0
}
return 0, 0, 0
}
func (a *Absence) Insert() error {
qStr, err := DB.Prepare(`INSERT INTO abwesenheit (card_uid, abwesenheit_typ, datum_from, datum_to) VALUES ($1, $2, $3, $4) RETURNING counter_id;`)
if err != nil {
log.Println("Error preparing sql Statement", err)
return err
}
defer qStr.Close()
err = qStr.QueryRow(a.CardUID, a.AbwesenheitTyp.Id, a.DateFrom, a.DateTo).Scan(&a.CounterId)
if err != nil {
log.Println("Error executing insert statement", err)
return err
}
return nil
}
func (a *Absence) Save() error {
qStr, err := DB.Prepare(`
UPDATE abwesenheit SET card_uid = $2, abwesenheit_typ = $3, datum_from = $4, datum_to = $5 WHERE counter_id = $1;
`)
if err != nil {
log.Println("Error preparing sql Statement (Absence Save)", err)
return err
}
defer qStr.Close()
_, err = qStr.Query(a.CounterId, a.CardUID, a.AbwesenheitTyp.Id, a.DateFrom, a.DateTo)
if err != nil {
log.Println("Error executing update statement", err)
return err
}
return nil
}
func GetAbsenceById(counterId int) (Absence, error) {
var absence Absence = Absence{CounterId: counterId}
qStr, err := DB.Prepare("SELECT card_uid, abwesenheit_typ, datum_from, datum_to FROM abwesenheit WHERE counter_id = $1;")
if err != nil {
return absence, err
}
defer qStr.Close()
err = qStr.QueryRow(counterId).Scan(&absence.CardUID, &absence.AbwesenheitTyp.Id, &absence.DateFrom, &absence.DateTo)
if err != nil {
return absence, err
}
return absence, nil
}
func GetAbsencesByCardUID(card_uid string, tsFrom time.Time, tsTo time.Time) ([]Absence, error) {
var absences []Absence
// qStr, err := DB.Prepare(`SELECT counter_id, abwesenheit_typ, datum_from, datum_to FROM abwesenheit WHERE card_uid = $1 AND datum_from <= $2 AND datum_to >= $3 ORDER BY datum_from;`)
qStr, err := DB.Prepare(`
SELECT
ab.counter_id,
gs::DATE AS work_date,
ab.card_uid,
ab.datum_from,
ab.datum_to,
jsonb_build_object(
'abwesenheit_id', sat.abwesenheit_id,
'abwesenheit_name', sat.abwesenheit_name,
'arbeitszeit_equivalent', sat.arbeitszeit_equivalent
) AS abwesenheit_info
FROM generate_series(
$2,
$3,
INTERVAL '1 day'
) gs
JOIN abwesenheit ab
ON ab.card_uid = $1
AND ab.datum_from::DATE <= gs::DATE
AND ab.datum_to::DATE >= gs::DATE
LEFT JOIN s_abwesenheit_typen sat
ON ab.abwesenheit_typ = sat.abwesenheit_id
ORDER BY gs::DATE, ab.counter_id;
`)
if err != nil {
return absences, err
}
defer qStr.Close()
rows, err := qStr.Query(card_uid, tsFrom, tsTo)
if err != nil {
return absences, err
}
defer rows.Close()
for rows.Next() {
var absence Absence
var abwesenheitsTyp []byte
if err := rows.Scan(&absence.CounterId, &absence.Day, &absence.CardUID, &absence.DateFrom, &absence.DateTo, &abwesenheitsTyp); err != nil {
return absences, err
}
err = json.Unmarshal(abwesenheitsTyp, &absence.AbwesenheitTyp)
if err != nil {
log.Println("Error parsing abwesenheitsTyp to JSON!", err)
return absences, nil
}
absences = append(absences, absence)
}
if err = rows.Err(); err != nil {
return absences, err
}
return absences, nil
}
func (a *Absence) Update(na Absence) bool {
change := false
if a.CardUID != na.CardUID && na.CardUID != "" {
a.CardUID = na.CardUID
change = true
}
if a.AbwesenheitTyp != na.AbwesenheitTyp && na.AbwesenheitTyp.Id != 0 {
a.AbwesenheitTyp = na.AbwesenheitTyp
change = true
}
if !a.DateFrom.Equal(na.DateFrom) && !na.DateFrom.IsZero() {
a.DateFrom = na.DateFrom
change = true
}
if !a.DateTo.Equal(na.DateTo) && !na.DateTo.IsZero() {
a.DateTo = na.DateTo
change = true
}
return change
}
func GetAbsenceTypes() (map[int8]AbsenceType, error) {
var types = make(map[int8]AbsenceType)
qStr, err := DB.Prepare("SELECT abwesenheit_id, abwesenheit_name, arbeitszeit_equivalent FROM s_abwesenheit_typen;")
if err != nil {
return types, err
}
defer qStr.Close()
rows, err := qStr.Query()
if err != nil {
log.Println("Error getting abwesenheit rows!", err)
return types, err
}
defer rows.Close()
for rows.Next() {
var absenceType AbsenceType
if err := rows.Scan(&absenceType.Id, &absenceType.Name, &absenceType.WorkTime); err != nil {
log.Println("Error scanning absence row!", err)
}
types[absenceType.Id] = absenceType
}
return types, nil
}
func GetAbsenceTypesCached() map[int8]AbsenceType {
types, err := definedTypes.Get("s_abwesenheit_typen")
if err != nil {
return map[int8]AbsenceType{}
}
return types.(map[int8]AbsenceType)
}
func GetAbsenceTypeById(absenceTypeId int8) (AbsenceType, error) {
var absenceType AbsenceType = AbsenceType{Id: absenceTypeId}
qStr, err := DB.Prepare("SELECT abwesenheit_name, arbeitszeit_equivalent FROM s_abwesenheit_typen WHERE abwesenheit_id = $1;")
if err != nil {
return absenceType, err
}
defer qStr.Close()
err = qStr.QueryRow(absenceTypeId).Scan(&absenceType.Name, &absenceType.WorkTime)
if err != nil {
return absenceType, err
}
return absenceType, nil
}