Some checks reported errors
arbeitszeitmessung/pipeline/head Something is wrong with the build of this commit
305 lines
7.8 KiB
Go
305 lines
7.8 KiB
Go
package models
|
|
|
|
import (
|
|
"arbeitszeitmessung/helper"
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
"net/url"
|
|
"sort"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type SameBookingError struct{}
|
|
|
|
type BookingType struct {
|
|
Id int8
|
|
Name string
|
|
}
|
|
|
|
func (e SameBookingError) Error() string {
|
|
return "the same booking already exists!"
|
|
}
|
|
|
|
type Booking struct {
|
|
CardUID string `json:"card_uid"`
|
|
GeraetID int16 `json:"geraet_id"`
|
|
CheckInOut int16 `json:"check_in_out"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
CounterId int `json:"counter_id"`
|
|
}
|
|
|
|
type IDatabase interface {
|
|
Prepare(query string) (*sql.Stmt, error)
|
|
Exec(query string, args ...any) (sql.Result, error)
|
|
}
|
|
|
|
var DB IDatabase
|
|
|
|
func (b *Booking) New(card_uid string, geraet_id int16, check_in_out int16) Booking {
|
|
return Booking{
|
|
CardUID: card_uid,
|
|
GeraetID: geraet_id,
|
|
CheckInOut: check_in_out,
|
|
}
|
|
}
|
|
|
|
func (b *Booking) FromUrlParams(params url.Values) Booking {
|
|
var booking Booking
|
|
if _check_in_out, err := strconv.Atoi(params.Get("check_in_out")); err == nil {
|
|
booking.CheckInOut = int16(_check_in_out)
|
|
}
|
|
if _geraet_id, err := strconv.Atoi(params.Get("geraet_id")); err == nil {
|
|
booking.GeraetID = int16(_geraet_id)
|
|
}
|
|
booking.CardUID = params.Get("card_uid")
|
|
return booking
|
|
}
|
|
|
|
func (b *Booking) Verify() bool {
|
|
//check for overlapping time + arbeitszeit verstoß
|
|
if b.CardUID == "" { //|| b.GeraetID == 0 || b.CheckInOut == 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (b *Booking) Insert() error {
|
|
if !checkLastBooking(*b) {
|
|
return SameBookingError{}
|
|
}
|
|
stmt, err := DB.Prepare((`INSERT INTO anwesenheit (card_uid, geraet_id, check_in_out) VALUES ($1, $2, $3) RETURNING counter_id, timestamp`))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = stmt.QueryRow(b.CardUID, b.GeraetID, b.CheckInOut).Scan(&b.CounterId, &b.Timestamp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *Booking) InsertWithTimestamp() error {
|
|
if b.Timestamp.IsZero() {
|
|
return b.Insert()
|
|
}
|
|
stmt, err := DB.Prepare((`INSERT INTO anwesenheit (card_uid, geraet_id, check_in_out, timestamp) VALUES ($1, $2, $3, $4) RETURNING counter_id`))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = stmt.QueryRow(b.CardUID, b.GeraetID, b.CheckInOut, b.Timestamp).Scan(&b.CounterId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *Booking) GetBookingById(booking_id int) (Booking, error) {
|
|
var booking Booking
|
|
qStr, err := DB.Prepare((`SELECT counter_id, timestamp, card_uid, geraet_id, check_in_out FROM anwesenheit WHERE counter_id = $1`))
|
|
if err != nil {
|
|
return booking, err
|
|
}
|
|
err = qStr.QueryRow(booking_id).Scan(&booking.CounterId, &booking.Timestamp, &booking.CardUID, &booking.GeraetID, &booking.CheckInOut)
|
|
if err != nil {
|
|
return booking, err
|
|
}
|
|
// if !booking.Verify() {
|
|
// fmt.Printf("Booking verification failed! %d", )
|
|
// return booking, nil
|
|
// }
|
|
return booking, nil
|
|
}
|
|
|
|
// Gets all booking based on a card uid
|
|
//
|
|
// optional filter parameter
|
|
func (b *Booking) GetBookingsByCardID(card_uid string, tsFrom time.Time, tsTo time.Time) ([]Booking, error) {
|
|
qStr, err := DB.Prepare((`SELECT counter_id, timestamp, card_uid, geraet_id, check_in_out FROM anwesenheit WHERE card_uid = $1 AND timestamp BETWEEN $2 AND $3 ORDER BY timestamp`))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer qStr.Close()
|
|
var bookings []Booking
|
|
rows, err := qStr.Query(card_uid, tsFrom, tsTo)
|
|
if err == sql.ErrNoRows {
|
|
return bookings, err
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var booking Booking
|
|
if err := rows.Scan(&booking.CounterId, &booking.Timestamp, &booking.CardUID, &booking.GeraetID, &booking.CheckInOut); err != nil {
|
|
return bookings, err
|
|
}
|
|
bookings = append(bookings, booking)
|
|
}
|
|
if err = rows.Err(); err != nil {
|
|
return bookings, err
|
|
}
|
|
return bookings, nil
|
|
}
|
|
|
|
func (b *Booking) GetBookingsGrouped(card_uid string, tsFrom time.Time, tsTo time.Time) ([]WorkDay, error) {
|
|
var grouped = make(map[string][]Booking)
|
|
bookings, err := b.GetBookingsByCardID(card_uid, tsFrom, tsTo)
|
|
if err != nil {
|
|
log.Println("Failed to get bookings", err)
|
|
return []WorkDay{}, nil
|
|
}
|
|
for _, booking := range bookings {
|
|
day := booking.Timestamp.Truncate(24 * time.Hour)
|
|
key := day.Format("2006-01-02")
|
|
grouped[key] = append(grouped[key], booking)
|
|
}
|
|
|
|
var result []WorkDay
|
|
for key, bookings := range grouped {
|
|
day, _ := time.Parse("2006-01-02", key)
|
|
sort.Slice(bookings, func(i, j int) bool {
|
|
return bookings[i].Timestamp.Before(bookings[j].Timestamp)
|
|
})
|
|
workDay := WorkDay{Day: day, Bookings: bookings}
|
|
workDay.getWorkTime()
|
|
result = append(result, workDay)
|
|
}
|
|
|
|
sort.Slice(result, func(i, j int) bool {
|
|
return result[i].Day.After(result[j].Day)
|
|
})
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (b Booking) Save() {
|
|
qStr, err := DB.Prepare((`UPDATE "anwesenheit" SET "card_uid" = $2, "geraet_id" = $3, "check_in_out" = $4, "timestamp" = $5 WHERE "counter_id" = $1;`))
|
|
if err != nil {
|
|
log.Fatalf("Error preparing query: %v", err)
|
|
return
|
|
}
|
|
_, err = qStr.Query(b.CounterId, b.CardUID, b.GeraetID, b.CheckInOut, b.Timestamp)
|
|
if err != nil {
|
|
log.Fatalf("Error executing query: %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (b *Booking) GetBookingType() string {
|
|
debug := (helper.GetEnv("GO_ENV", "production") == "debug")
|
|
switch b.CheckInOut {
|
|
case 1: //manuelle Änderung
|
|
return "kommen"
|
|
case 3:
|
|
if debug {
|
|
return "kommen manuell"
|
|
}
|
|
return "kommen"
|
|
case 2: //manuelle Änderung
|
|
return "gehen"
|
|
case 4:
|
|
if debug {
|
|
return "gehen manuell"
|
|
}
|
|
return "gehen"
|
|
case 254:
|
|
return "abgemeldet"
|
|
default:
|
|
return "Buchungs Typ unbekannt"
|
|
}
|
|
}
|
|
|
|
func (b *Booking) Update(nb Booking) {
|
|
if b.CheckInOut != nb.CheckInOut && nb.CheckInOut != 0 {
|
|
b.CheckInOut = nb.CheckInOut
|
|
}
|
|
if b.CardUID != nb.CardUID && nb.CardUID != "" {
|
|
b.CardUID = nb.CardUID
|
|
}
|
|
if b.GeraetID != nb.GeraetID && nb.GeraetID != 0 {
|
|
b.GeraetID = nb.GeraetID
|
|
}
|
|
if b.Timestamp != nb.Timestamp {
|
|
b.Timestamp = nb.Timestamp
|
|
}
|
|
}
|
|
|
|
func checkLastBooking(b Booking) bool {
|
|
var check_in_out int
|
|
stmt, err := DB.Prepare((`SELECT check_in_out FROM "anwesenheit" WHERE "card_uid" = $1 ORDER BY "timestamp" DESC LIMIT 1;`))
|
|
if err != nil {
|
|
log.Fatalf("Error preparing query: %v", err)
|
|
return false
|
|
}
|
|
err = stmt.QueryRow(b.CardUID).Scan(&check_in_out)
|
|
if err == sql.ErrNoRows {
|
|
return true
|
|
}
|
|
if err != nil {
|
|
log.Println("Error checking last booking: ", err)
|
|
return false
|
|
}
|
|
if int16(check_in_out)%2 == b.CheckInOut%2 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (b *Booking) UpdateTime(newTime time.Time) {
|
|
hour, minute, _ := newTime.Clock()
|
|
if hour == b.Timestamp.Hour() && minute == b.Timestamp.Minute() {
|
|
return
|
|
}
|
|
// TODO: add check for time overlap
|
|
|
|
var newBooking Booking
|
|
newBooking.Timestamp = time.Date(b.Timestamp.Year(), b.Timestamp.Month(), b.Timestamp.Day(), hour, minute, 0, 0, b.Timestamp.Location())
|
|
if b.CheckInOut < 3 {
|
|
newBooking.CheckInOut = b.CheckInOut + 2
|
|
}
|
|
if b.CheckInOut == 254 {
|
|
newBooking.CheckInOut = 4
|
|
}
|
|
log.Println("Updating")
|
|
b.Update(newBooking)
|
|
b.Verify()
|
|
b.Save()
|
|
}
|
|
|
|
func (b *Booking) ToString() string {
|
|
return fmt.Sprintf("Booking %d: at: %s, as type: %d", b.CounterId, b.Timestamp.Format("15:04"), b.CheckInOut)
|
|
}
|
|
|
|
func GetBokkingTypes() ([]BookingType, error) {
|
|
var types []BookingType
|
|
qStr, err := DB.Prepare("SELECT anwesenheit_id, anwesenheit_name FROM s_anwesenheit_typen;")
|
|
if err != nil {
|
|
return types, err
|
|
}
|
|
defer qStr.Close()
|
|
rows, err := qStr.Query()
|
|
if err != nil {
|
|
log.Println("Error getting anwesenheit rows!", err)
|
|
return types, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var bookingType BookingType
|
|
if err := rows.Scan(&bookingType.Id, &bookingType.Name); err != nil {
|
|
log.Println("Error scanning row!", err)
|
|
}
|
|
types = append(types, bookingType)
|
|
}
|
|
return types, nil
|
|
}
|
|
|
|
func GetBookingTypesCached() []BookingType {
|
|
types, err := definedTypes.Get("s_anwesenheit_typen")
|
|
if err != nil {
|
|
return []BookingType{}
|
|
}
|
|
return types.([]BookingType)
|
|
}
|