added absence - abwesenheit, closes #11

This commit is contained in:
2025-05-19 21:42:30 +02:00
parent 37458d8ffb
commit df3779d264
10 changed files with 311 additions and 173 deletions

View File

@@ -1,6 +1,38 @@
package models
import "time"
import (
"log"
"time"
)
type AbsenceType struct {
Value int8
Label string
}
const (
AbsenceNone int8 = iota
AbsenceUrlaub
AbsenceKurzarbeit
AbsenceKrank
AbsenceKindkrank
)
var AbsenceTypes = []AbsenceType{
// {Value: AbsenceNone, Label: "Abwesenheit"},
{Value: AbsenceUrlaub, Label: "Urlaub"},
{Value: AbsenceKurzarbeit, Label: "Kurzarbeit"},
{Value: AbsenceKrank, Label: "Krank"},
{Value: AbsenceKindkrank, Label: "Kindkrank"},
}
var AbsenceTypesLabel = map[int8]string{
0: "None",
AbsenceUrlaub: "Urlaub",
AbsenceKurzarbeit: "Kurzarbeit",
AbsenceKrank: "Krank",
AbsenceKindkrank: "Kindkrank",
}
type Absence struct {
CounterId int
@@ -17,6 +49,20 @@ func NewAbsence(card_uid string, abwesenheit_typ int8, datum time.Time) Absence
}
}
func (a *Absence) Insert() {
// qStr, err := DB.Prepare(`INSERT INTO`)
func (a *Absence) Insert() error {
qStr, err := DB.Prepare(`INSERT INTO abwesenheit (card_uid, abwesenheit_typ, datum) VALUES ($1, $2, $3) RETURNING counter_id;`)
if err != nil {
log.Println("Error preparing sql Statement", err)
return err
}
err = qStr.QueryRow(a.CardUID, a.AbwesenheitTyp, a.Datum).Scan(&a.CounterId)
if err != nil {
log.Println("Error executing insert statement", err)
return err
}
return nil
}
func (a *Absence) GetStringType() string {
return AbsenceTypesLabel[a.AbwesenheitTyp]
}

View File

@@ -2,6 +2,7 @@ package models
import (
"arbeitszeitmessung/helper"
"database/sql"
"encoding/json"
"fmt"
"log"
@@ -16,6 +17,7 @@ type WorkDay struct {
pauseTime time.Duration
TimeFrom time.Time
TimeTo time.Time
Absence Absence
}
func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay {
@@ -23,8 +25,8 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
var workSec, pauseSec float64
qStr, err := DB.Prepare(`
WITH all_days AS (
SELECT generate_series($2::DATE, $3::DATE - INTERVAL '1 day', INTERVAL '1 day')::DATE AS work_date
WITH all_days AS (
SELECT generate_series($2, $3, INTERVAL '1 day')::DATE AS work_date
),
ordered_bookings AS (
SELECT
@@ -38,6 +40,15 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
WHERE card_uid = $1
AND timestamp::DATE >= $2
AND timestamp::DATE <= $3
),
abwesenheiten AS (
SELECT
datum::DATE AS work_date,
abwesenheit_typ
FROM abwesenheit
WHERE card_uid = $1
AND datum::DATE >= $2
AND datum::DATE <= $3
)
SELECT
d.work_date,
@@ -46,7 +57,7 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
COALESCE(
EXTRACT(EPOCH FROM SUM(
CASE
WHEN b.prev_check IN (1, 3) AND b.check_in_out IN (2, 4, 254)
WHEN b.prev_check IN (1, 3) AND b.check_in_out IN (2, 4, 255)
THEN b.timestamp - b.prev_timestamp
ELSE INTERVAL '0'
END
@@ -55,7 +66,7 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
COALESCE(
EXTRACT(EPOCH FROM SUM(
CASE
WHEN b.prev_check IN (2, 4, 254) AND b.check_in_out IN (1, 3)
WHEN b.prev_check IN (2, 4, 255) AND b.check_in_out IN (1, 3)
THEN b.timestamp - b.prev_timestamp
ELSE INTERVAL '0'
END
@@ -65,10 +76,12 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
'check_in_out', b.check_in_out,
'timestamp', b.timestamp,
'counter_id', b.counter_id
) ORDER BY b.timestamp), '[]'::jsonb) AS bookings
) ORDER BY b.timestamp), '[]'::jsonb) AS bookings,
a.abwesenheit_typ
FROM all_days d
LEFT JOIN ordered_bookings b ON d.work_date = b.work_date
GROUP BY d.work_date
LEFT JOIN abwesenheiten a ON d.work_date = a.work_date
GROUP BY d.work_date, a.abwesenheit_typ
ORDER BY d.work_date;`)
if err != nil {
@@ -87,7 +100,8 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
for rows.Next() {
var workDay WorkDay
var bookings []byte
if err := rows.Scan(&workDay.Day, &workDay.TimeFrom, &workDay.TimeTo, &workSec, &pauseSec, &bookings); err != nil {
var absenceType sql.NullInt16
if err := rows.Scan(&workDay.Day, &workDay.TimeFrom, &workDay.TimeTo, &workSec, &pauseSec, &bookings, &absenceType); err != nil {
log.Println("Error scanning row!", err)
return workDays
}
@@ -98,6 +112,15 @@ func (d *WorkDay) GetWorkDays(card_uid string, tsFrom, tsTo time.Time) []WorkDay
log.Println("Error parsing bookings JSON!", err)
return nil
}
// better empty day handling
if len(workDay.Bookings) == 1 && workDay.Bookings[0].CounterId == 0 {
workDay.Bookings = []Booking{}
}
if absenceType.Valid {
workDay.Absence = NewAbsence(card_uid, int8(absenceType.Int16), workDay.Day)
log.Println("Found absence", workDay.Absence)
}
if workDay.Day.Equal(time.Now().Truncate(24 * time.Hour)) {
workDay.getWorkTime()
@@ -179,7 +202,10 @@ func (d *WorkDay) GetWorkTimeString() (string, string) {
// returns bool wheter the workday was ended with an automatic logout
func (d *WorkDay) RequiresAction() bool {
return d.Bookings[len(d.Bookings)-1].CheckInOut == 254
if len(d.Bookings) > 0 {
return d.Bookings[len(d.Bookings)-1].CheckInOut == 254
}
return false
}
// returns a integer percentage of how much day has been worked of

View File

@@ -18,9 +18,9 @@ type WorkWeek struct {
type WeekStatus int8
const (
None WeekStatus = iota
Sent
Accepted
WeekStatusNone WeekStatus = iota
WeekStatusSent
WeekStatusAccepted
)
func (w *WorkWeek) GetWeek(user User, tsMonday time.Time, populateDays bool) WorkWeek {
@@ -35,7 +35,7 @@ func (w *WorkWeek) GetWeek(user User, tsMonday time.Time, populateDays bool) Wor
}
func (w *WorkWeek) CheckStatus() WeekStatus {
weekStatus := None
weekStatus := WeekStatusNone
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)
@@ -52,9 +52,9 @@ func (w *WorkWeek) CheckStatus() WeekStatus {
return weekStatus
}
if beastatigt {
weekStatus = Accepted
weekStatus = WeekStatusAccepted
} else {
weekStatus = Sent
weekStatus = WeekStatusSent
}
return weekStatus
}
@@ -114,7 +114,7 @@ func (w *WorkWeek) Send() error {
log.Println("Cannot send week, because it's the running week!")
return ErrRunningWeek
}
if w.CheckStatus() != None {
if w.CheckStatus() != WeekStatusNone {
qStr, err = DB.Prepare(`UPDATE "wochen_report" SET bestaetigt = FALSE WHERE personal_nummer = $1 AND woche_start = $2;`)
if err != nil {
log.Println("Error preparing SQL statement", err)