dev/actions feature: overtime #27
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Ensure all text files use LF line endings
|
||||||
|
* text=auto eol=lf
|
||||||
@@ -50,8 +50,9 @@ func createBooking(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusAccepted)
|
w.WriteHeader(http.StatusAccepted)
|
||||||
json.NewEncoder(w).Encode(booking)
|
json.NewEncoder(w).Encode(booking)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
http.Error(w, "Cannot verify booking, maybe missing a parameter", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyToken(r *http.Request) bool {
|
func verifyToken(r *http.Request) bool {
|
||||||
|
|||||||
@@ -110,11 +110,11 @@ func updateBooking(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newBooking := (*models.Booking).New(nil, user.CardUID, 0, int16(check_in_out))
|
newBooking := (*models.Booking).New(nil, user.CardUID, 0, int16(check_in_out), 1)
|
||||||
newBooking.Timestamp = timestamp
|
newBooking.Timestamp = timestamp
|
||||||
err = newBooking.InsertWithTimestamp()
|
err = newBooking.InsertWithTimestamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error inserting booking", err)
|
log.Printf("Error inserting booking %v -> %v\n", newBooking, err)
|
||||||
}
|
}
|
||||||
case "change":
|
case "change":
|
||||||
absenceType, err := strconv.Atoi(r.FormValue("absence"))
|
absenceType, err := strconv.Atoi(r.FormValue("absence"))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
func TestGetMonday(t *testing.T) {
|
func TestGetMonday(t *testing.T) {
|
||||||
isMonday, err := time.Parse("2006-01-02", "2025-07-14")
|
isMonday, err := time.Parse("2006-01-02", "2025-07-14")
|
||||||
notMonday, err := time.Parse("2006-01-02", "2025-07-16")
|
notMonday, err := time.Parse("2006-01-02", "2025-07-16")
|
||||||
if err != nil || isMonday == notMonday {
|
if err != nil || isMonday.Equal(notMonday) {
|
||||||
t.Errorf("U stupid? %e", err)
|
t.Errorf("U stupid? %e", err)
|
||||||
}
|
}
|
||||||
if GetMonday(isMonday) != isMonday || GetMonday(notMonday) != isMonday {
|
if GetMonday(isMonday) != isMonday || GetMonday(notMonday) != isMonday {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ type Booking struct {
|
|||||||
CheckInOut int16 `json:"check_in_out"`
|
CheckInOut int16 `json:"check_in_out"`
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
CounterId int `json:"counter_id"`
|
CounterId int `json:"counter_id"`
|
||||||
|
BookingType BookingType `json:"booking_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IDatabase interface {
|
type IDatabase interface {
|
||||||
@@ -37,31 +38,52 @@ type IDatabase interface {
|
|||||||
|
|
||||||
var DB IDatabase
|
var DB IDatabase
|
||||||
|
|
||||||
func (b *Booking) New(card_uid string, geraet_id int16, check_in_out int16) Booking {
|
func (b *Booking) New(cardUid string, gereatId int16, checkInOut int16, typeId int8) Booking {
|
||||||
|
bookingType, err := GetBookingTypeById(typeId)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Cannot get booking type %d, from database!", typeId)
|
||||||
|
}
|
||||||
return Booking{
|
return Booking{
|
||||||
CardUID: card_uid,
|
CardUID: cardUid,
|
||||||
GeraetID: geraet_id,
|
GeraetID: gereatId,
|
||||||
CheckInOut: check_in_out,
|
CheckInOut: checkInOut,
|
||||||
|
BookingType: bookingType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Booking) FromUrlParams(params url.Values) Booking {
|
func (b *Booking) FromUrlParams(params url.Values) Booking {
|
||||||
var booking Booking
|
var booking Booking
|
||||||
|
|
||||||
if _check_in_out, err := strconv.Atoi(params.Get("check_in_out")); err == nil {
|
if _check_in_out, err := strconv.Atoi(params.Get("check_in_out")); err == nil {
|
||||||
booking.CheckInOut = int16(_check_in_out)
|
booking.CheckInOut = int16(_check_in_out)
|
||||||
}
|
}
|
||||||
if _geraet_id, err := strconv.Atoi(params.Get("geraet_id")); err == nil {
|
if _geraet_id, err := strconv.Atoi(params.Get("geraet_id")); err == nil {
|
||||||
booking.GeraetID = int16(_geraet_id)
|
booking.GeraetID = int16(_geraet_id)
|
||||||
}
|
}
|
||||||
|
if _booking_type, err := strconv.Atoi(params.Get("booking_type")); err == nil {
|
||||||
|
booking.BookingType.Id = int8(_booking_type)
|
||||||
|
}
|
||||||
booking.CardUID = params.Get("card_uid")
|
booking.CardUID = params.Get("card_uid")
|
||||||
|
|
||||||
return booking
|
return booking
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Booking) Verify() bool {
|
func (b *Booking) Verify() bool {
|
||||||
//check for overlapping time + arbeitszeit verstoß
|
//check for overlapping time + arbeitszeit verstoß
|
||||||
if b.CardUID == "" { //|| b.GeraetID == 0 || b.CheckInOut == 0 {
|
if b.CardUID == "" { //|| b.GeraetID == 0 || b.CheckInOut == 0 {
|
||||||
|
log.Println("Booking verify failed invalid CardUID!")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if b.CheckInOut == 0 {
|
||||||
|
log.Println("Booking verify failed invalid CheckInOut!")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if bookingType, err := GetBookingTypeById(b.BookingType.Id); err != nil {
|
||||||
|
log.Println("Booking verify failed invalid BookingType.Id!")
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
b.BookingType.Name = bookingType.Name
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,11 +91,11 @@ func (b *Booking) Insert() error {
|
|||||||
if !checkLastBooking(*b) {
|
if !checkLastBooking(*b) {
|
||||||
return SameBookingError{}
|
return SameBookingError{}
|
||||||
}
|
}
|
||||||
stmt, err := DB.Prepare((`INSERT INTO anwesenheit (card_uid, geraet_id, check_in_out) VALUES ($1, $2, $3) RETURNING counter_id, timestamp`))
|
stmt, err := DB.Prepare((`INSERT INTO anwesenheit (card_uid, geraet_id, check_in_out, anwesenheit_typ) VALUES ($1, $2, $3, $4) RETURNING counter_id, timestamp`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = stmt.QueryRow(b.CardUID, b.GeraetID, b.CheckInOut).Scan(&b.CounterId, &b.Timestamp)
|
err = stmt.QueryRow(b.CardUID, b.GeraetID, b.CheckInOut, b.BookingType.Id).Scan(&b.CounterId, &b.Timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -84,11 +106,11 @@ func (b *Booking) InsertWithTimestamp() error {
|
|||||||
if b.Timestamp.IsZero() {
|
if b.Timestamp.IsZero() {
|
||||||
return b.Insert()
|
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`))
|
stmt, err := DB.Prepare((`INSERT INTO anwesenheit (card_uid, geraet_id, check_in_out, anwesenheit_typ, timestamp) VALUES ($1, $2, $3, $4, $5) RETURNING counter_id`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = stmt.QueryRow(b.CardUID, b.GeraetID, b.CheckInOut, b.Timestamp).Scan(&b.CounterId)
|
err = stmt.QueryRow(b.CardUID, b.GeraetID, b.CheckInOut, b.BookingType.Id, b.Timestamp).Scan(&b.CounterId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -97,18 +119,15 @@ func (b *Booking) InsertWithTimestamp() error {
|
|||||||
|
|
||||||
func (b *Booking) GetBookingById(booking_id int) (Booking, error) {
|
func (b *Booking) GetBookingById(booking_id int) (Booking, error) {
|
||||||
var booking Booking
|
var booking Booking
|
||||||
qStr, err := DB.Prepare((`SELECT counter_id, timestamp, card_uid, geraet_id, check_in_out FROM anwesenheit WHERE counter_id = $1`))
|
qStr, err := DB.Prepare((`SELECT counter_id, timestamp, card_uid, geraet_id, check_in_out, anwesenheit_typ FROM anwesenheit WHERE counter_id = $1`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return booking, err
|
return booking, err
|
||||||
}
|
}
|
||||||
err = qStr.QueryRow(booking_id).Scan(&booking.CounterId, &booking.Timestamp, &booking.CardUID, &booking.GeraetID, &booking.CheckInOut)
|
// TODO: also get booking type name
|
||||||
|
err = qStr.QueryRow(booking_id).Scan(&booking.CounterId, &booking.Timestamp, &booking.CardUID, &booking.GeraetID, &booking.CheckInOut, &booking.BookingType.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return booking, err
|
return booking, err
|
||||||
}
|
}
|
||||||
// if !booking.Verify() {
|
|
||||||
// fmt.Printf("Booking verification failed! %d", )
|
|
||||||
// return booking, nil
|
|
||||||
// }
|
|
||||||
return booking, nil
|
return booking, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +283,7 @@ func (b *Booking) UpdateTime(newTime time.Time) {
|
|||||||
}
|
}
|
||||||
log.Println("Updating")
|
log.Println("Updating")
|
||||||
b.Update(newBooking)
|
b.Update(newBooking)
|
||||||
|
// TODO Check verify
|
||||||
b.Verify()
|
b.Verify()
|
||||||
b.Save()
|
b.Save()
|
||||||
}
|
}
|
||||||
@@ -272,7 +292,7 @@ func (b *Booking) ToString() string {
|
|||||||
return fmt.Sprintf("Booking %d: at: %s, as type: %d", b.CounterId, b.Timestamp.Format("15:04"), b.CheckInOut)
|
return fmt.Sprintf("Booking %d: at: %s, as type: %d", b.CounterId, b.Timestamp.Format("15:04"), b.CheckInOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBokkingTypes() ([]BookingType, error) {
|
func GetBookingTypes() ([]BookingType, error) {
|
||||||
var types []BookingType
|
var types []BookingType
|
||||||
qStr, err := DB.Prepare("SELECT anwesenheit_id, anwesenheit_name FROM s_anwesenheit_typen;")
|
qStr, err := DB.Prepare("SELECT anwesenheit_id, anwesenheit_name FROM s_anwesenheit_typen;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -295,6 +315,21 @@ func GetBokkingTypes() ([]BookingType, error) {
|
|||||||
return types, nil
|
return types, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetBookingTypeById(bookingTypeId int8) (BookingType, error) {
|
||||||
|
var bookingType BookingType = BookingType{Id: bookingTypeId}
|
||||||
|
|
||||||
|
qStr, err := DB.Prepare("SELECT anwesenheit_name FROM s_anwesenheit_typen WHERE anwesenheit_id = $1;")
|
||||||
|
if err != nil {
|
||||||
|
return bookingType, err
|
||||||
|
}
|
||||||
|
defer qStr.Close()
|
||||||
|
err = qStr.QueryRow(bookingTypeId).Scan(&bookingType.Name)
|
||||||
|
if err != nil {
|
||||||
|
return bookingType, err
|
||||||
|
}
|
||||||
|
return bookingType, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetBookingTypesCached() []BookingType {
|
func GetBookingTypesCached() []BookingType {
|
||||||
types, err := definedTypes.Get("s_anwesenheit_typen")
|
types, err := definedTypes.Get("s_anwesenheit_typen")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ var definedTypes = helper.NewCache(3600, func(key string) (any, error) {
|
|||||||
case "s_abwesenheit_typen":
|
case "s_abwesenheit_typen":
|
||||||
return GetAbsenceTypes()
|
return GetAbsenceTypes()
|
||||||
case "s_anwesenheit_typen":
|
case "s_anwesenheit_typen":
|
||||||
return GetBokkingTypes()
|
return GetBookingTypes()
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
})
|
})
|
||||||
@@ -86,10 +86,10 @@ func (u *User) CheckAnwesenheit() bool {
|
|||||||
|
|
||||||
// Creates a new booking for the user -> check_in_out will be 254 for automatic check out
|
// Creates a new booking for the user -> check_in_out will be 254 for automatic check out
|
||||||
func (u *User) CheckOut() error {
|
func (u *User) CheckOut() error {
|
||||||
booking := (*Booking).New(nil, u.CardUID, 0, 254)
|
booking := (*Booking).New(nil, u.CardUID, 0, 254, 1)
|
||||||
err := booking.Insert()
|
err := booking.Insert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error inserting booking %v\n", err)
|
fmt.Printf("Error inserting booking %v -> %v\n", booking, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ CREATE TABLE "anwesenheit" (
|
|||||||
"card_uid" character varying(255) NOT NULL,
|
"card_uid" character varying(255) NOT NULL,
|
||||||
"check_in_out" smallint NOT NULL,
|
"check_in_out" smallint NOT NULL,
|
||||||
"geraet_id" smallint NULL,
|
"geraet_id" smallint NULL,
|
||||||
-- "anwesenheit_typ" int2,
|
"anwesenheit_typ" int2,
|
||||||
PRIMARY KEY ("counter_id")
|
PRIMARY KEY ("counter_id")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
PGDATA: /var/lib/postgresql/data/pg_data
|
PGDATA: /var/lib/postgresql/data/pg_data
|
||||||
volumes:
|
volumes:
|
||||||
- ${POSTGRES_PATH}:/var/lib/postgresql/data
|
- ${POSTGRES_PATH}:/var/lib/postgresql/data
|
||||||
- ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d
|
# - ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
|
|
||||||
|
|||||||
48
db.sql
48
db.sql
@@ -146,3 +146,51 @@ SELECT
|
|||||||
FROM ordered_bookings
|
FROM ordered_bookings
|
||||||
GROUP BY work_date
|
GROUP BY work_date
|
||||||
ORDER BY work_date;
|
ORDER BY work_date;
|
||||||
|
|
||||||
|
|
||||||
|
-- Generate weekdays for 2 weeks (Mon–Fri), starting 2 weeks ago
|
||||||
|
WITH days AS (
|
||||||
|
SELECT gs::date AS work_date
|
||||||
|
FROM generate_series(
|
||||||
|
date_trunc('week', CURRENT_DATE) - interval '14 days', -- start 2 weeks ago Monday
|
||||||
|
CURRENT_DATE, -- end TODAY (no future days)
|
||||||
|
interval '1 day'
|
||||||
|
) gs
|
||||||
|
WHERE EXTRACT(ISODOW FROM gs) <= 5 -- only Mon–Fri
|
||||||
|
),
|
||||||
|
sample_bookings AS (
|
||||||
|
SELECT
|
||||||
|
d.work_date,
|
||||||
|
'aaaa-aaaa'::varchar AS card_uid,
|
||||||
|
1 AS check_in_out, -- come
|
||||||
|
101 AS geraet_id,
|
||||||
|
(d.work_date + make_time(8, floor(random()*50)::int, 0))::timestamptz AS ts,
|
||||||
|
1 AS anwesenheit_typ
|
||||||
|
FROM days d
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
d.work_date,
|
||||||
|
'aaaa-aaaa'::varchar AS card_uid,
|
||||||
|
2 AS check_in_out, -- go
|
||||||
|
101 AS geraet_id,
|
||||||
|
(d.work_date + make_time(16, floor(random()*50)::int, 0))::timestamptz AS ts,
|
||||||
|
1 AS anwesenheit_typ
|
||||||
|
FROM days d
|
||||||
|
),
|
||||||
|
ins_anw AS (
|
||||||
|
-- insert only bookings up to now (prevents future times on today)
|
||||||
|
INSERT INTO anwesenheit ("timestamp", card_uid, check_in_out, geraet_id)
|
||||||
|
SELECT ts, card_uid, check_in_out, geraet_id
|
||||||
|
FROM sample_bookings
|
||||||
|
WHERE ts <= NOW()
|
||||||
|
RETURNING 1
|
||||||
|
)
|
||||||
|
-- now insert absences (uses the same days CTE)
|
||||||
|
INSERT INTO abwesenheit (card_uid, abwesenheit_typ, datum)
|
||||||
|
SELECT
|
||||||
|
'aaaa-aaaa',
|
||||||
|
(ARRAY[1, 2])[floor(random()*2 + 1)], -- example types
|
||||||
|
d.work_date::timestamptz
|
||||||
|
FROM days d
|
||||||
|
WHERE random() < 0.2 -- ~20% random absences
|
||||||
|
ORDER BY d.work_date;
|
||||||
|
|||||||
16
migrations/20250901201159_initial.down.sql
Normal file
16
migrations/20250901201159_initial.down.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
-- reverse: create "wochen_report" table
|
||||||
|
DROP TABLE "wochen_report";
|
||||||
|
-- reverse: create "user_password" table
|
||||||
|
DROP TABLE "user_password";
|
||||||
|
-- reverse: set comment to column: "geschlecht" on table: "personal_daten"
|
||||||
|
COMMENT ON COLUMN "personal_daten"."geschlecht" IS NULL;
|
||||||
|
-- reverse: create "personal_daten" table
|
||||||
|
DROP TABLE "personal_daten";
|
||||||
|
-- reverse: set comment to column: "geraet_id" on table: "anwesenheit"
|
||||||
|
COMMENT ON COLUMN "anwesenheit"."geraet_id" IS NULL;
|
||||||
|
-- reverse: set comment to column: "check_in_out" on table: "anwesenheit"
|
||||||
|
COMMENT ON COLUMN "anwesenheit"."check_in_out" IS NULL;
|
||||||
|
-- reverse: create "anwesenheit" table
|
||||||
|
DROP TABLE "anwesenheit";
|
||||||
|
-- reverse: create "abwesenheit" table
|
||||||
|
DROP TABLE "abwesenheit";
|
||||||
57
migrations/20250901201159_initial.up.sql
Normal file
57
migrations/20250901201159_initial.up.sql
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
-- create "abwesenheit" table
|
||||||
|
CREATE TABLE "abwesenheit" (
|
||||||
|
"counter_id" bigserial NOT NULL,
|
||||||
|
"card_uid" character varying(255) NULL,
|
||||||
|
"abwesenheit_typ" smallint NULL,
|
||||||
|
"datum" timestamptz NULL DEFAULT (now())::date,
|
||||||
|
PRIMARY KEY ("counter_id")
|
||||||
|
);
|
||||||
|
-- create "anwesenheit" table
|
||||||
|
CREATE TABLE "anwesenheit" (
|
||||||
|
"counter_id" bigserial NOT NULL,
|
||||||
|
"timestamp" timestamptz NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"card_uid" character varying(255) NULL,
|
||||||
|
"check_in_out" smallint NULL,
|
||||||
|
"geraet_id" smallint NULL,
|
||||||
|
PRIMARY KEY ("counter_id")
|
||||||
|
);
|
||||||
|
-- set comment to column: "check_in_out" on table: "anwesenheit"
|
||||||
|
COMMENT ON COLUMN "anwesenheit"."check_in_out" IS '1=Check In 2=Check Out , 3=Check in Manuell, 4=Check out manuell255=Automatic Check Out';
|
||||||
|
-- set comment to column: "geraet_id" on table: "anwesenheit"
|
||||||
|
COMMENT ON COLUMN "anwesenheit"."geraet_id" IS 'ID des Lesegerätes';
|
||||||
|
-- create "personal_daten" table
|
||||||
|
CREATE TABLE "personal_daten" (
|
||||||
|
"personal_nummer" integer NOT NULL,
|
||||||
|
"aktiv_beschaeftigt" boolean NULL,
|
||||||
|
"vorname" character varying(255) NULL,
|
||||||
|
"nachname" character varying(255) NULL,
|
||||||
|
"geburtsdatum" date NULL,
|
||||||
|
"plz" character varying(255) NULL,
|
||||||
|
"adresse" character varying(255) NULL,
|
||||||
|
"geschlecht" smallint NULL,
|
||||||
|
"card_uid" character varying(255) NULL,
|
||||||
|
"hauptbeschaeftigungs_ort" smallint NULL,
|
||||||
|
"arbeitszeit_per_tag" real NULL,
|
||||||
|
"arbeitszeit_min_start" time NULL,
|
||||||
|
"arbeitszeit_max_ende" time NULL,
|
||||||
|
"vorgesetzter_pers_nr" integer NULL,
|
||||||
|
PRIMARY KEY ("personal_nummer")
|
||||||
|
);
|
||||||
|
-- set comment to column: "geschlecht" on table: "personal_daten"
|
||||||
|
COMMENT ON COLUMN "personal_daten"."geschlecht" IS '1==weiblich, 2==maennlich, 3==divers';
|
||||||
|
-- create "user_password" table
|
||||||
|
CREATE TABLE "user_password" (
|
||||||
|
"personal_nummer" integer NOT NULL,
|
||||||
|
"pass_hash" text NULL,
|
||||||
|
"zuletzt_geandert" timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY ("personal_nummer")
|
||||||
|
);
|
||||||
|
-- create "wochen_report" table
|
||||||
|
CREATE TABLE "wochen_report" (
|
||||||
|
"id" serial NOT NULL,
|
||||||
|
"personal_nummer" integer NULL,
|
||||||
|
"woche_start" date NULL,
|
||||||
|
"bestaetigt" boolean NULL DEFAULT false,
|
||||||
|
PRIMARY KEY ("id"),
|
||||||
|
CONSTRAINT "wochen_report_personal_nummer_woche_start_key" UNIQUE ("personal_nummer", "woche_start")
|
||||||
|
);
|
||||||
31
migrations/20250901201250_control_tables.down.sql
Normal file
31
migrations/20250901201250_control_tables.down.sql
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-- reverse: drop "personal_daten" table
|
||||||
|
CREATE TABLE "personal_daten" (
|
||||||
|
"personal_nummer" integer NOT NULL,
|
||||||
|
"aktiv_beschaeftigt" boolean NULL,
|
||||||
|
"vorname" character varying(255) NULL,
|
||||||
|
"nachname" character varying(255) NULL,
|
||||||
|
"geburtsdatum" date NULL,
|
||||||
|
"plz" character varying(255) NULL,
|
||||||
|
"adresse" character varying(255) NULL,
|
||||||
|
"geschlecht" smallint NULL,
|
||||||
|
"card_uid" character varying(255) NULL,
|
||||||
|
"hauptbeschaeftigungs_ort" smallint NULL,
|
||||||
|
"arbeitszeit_per_tag" real NULL,
|
||||||
|
"arbeitszeit_min_start" time NULL,
|
||||||
|
"arbeitszeit_max_ende" time NULL,
|
||||||
|
"vorgesetzter_pers_nr" integer NULL,
|
||||||
|
PRIMARY KEY ("personal_nummer")
|
||||||
|
);
|
||||||
|
COMMENT ON COLUMN "personal_daten"."geschlecht" IS '1==weiblich, 2==maennlich, 3==divers';
|
||||||
|
-- reverse: set comment to column: "geschlecht" on table: "s_personal_daten"
|
||||||
|
COMMENT ON COLUMN "s_personal_daten"."geschlecht" IS NULL;
|
||||||
|
-- reverse: create "s_personal_daten" table
|
||||||
|
DROP TABLE "s_personal_daten";
|
||||||
|
-- reverse: create "s_anwesenheit_typen" table
|
||||||
|
DROP TABLE "s_anwesenheit_typen";
|
||||||
|
-- reverse: create "s_abwesenheit_typen" table
|
||||||
|
DROP TABLE "s_abwesenheit_typen";
|
||||||
|
-- reverse: modify "wochen_report" table
|
||||||
|
ALTER TABLE "wochen_report" DROP COLUMN "ueberstunden";
|
||||||
|
-- reverse: modify "anwesenheit" table
|
||||||
|
ALTER TABLE "anwesenheit" DROP COLUMN "anwesenheit_typ", ALTER COLUMN "check_in_out" DROP NOT NULL, ALTER COLUMN "card_uid" DROP NOT NULL;
|
||||||
38
migrations/20250901201250_control_tables.up.sql
Normal file
38
migrations/20250901201250_control_tables.up.sql
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
-- modify "anwesenheit" table
|
||||||
|
ALTER TABLE "anwesenheit" ALTER COLUMN "card_uid" SET NOT NULL, ALTER COLUMN "check_in_out" SET NOT NULL, ADD COLUMN "anwesenheit_typ" smallint NULL;
|
||||||
|
-- modify "wochen_report" table
|
||||||
|
ALTER TABLE "wochen_report" ADD COLUMN "ueberstunden" smallint NULL;
|
||||||
|
-- create "s_abwesenheit_typen" table
|
||||||
|
CREATE TABLE "s_abwesenheit_typen" (
|
||||||
|
"abwesenheit_id" smallint NOT NULL,
|
||||||
|
"abwesenheit_name" character varying(255) NULL,
|
||||||
|
PRIMARY KEY ("abwesenheit_id")
|
||||||
|
);
|
||||||
|
-- create "s_anwesenheit_typen" table
|
||||||
|
CREATE TABLE "s_anwesenheit_typen" (
|
||||||
|
"anwesenheit_id" smallint NOT NULL,
|
||||||
|
"anwesenheit_name" character varying(255) NULL,
|
||||||
|
PRIMARY KEY ("anwesenheit_id")
|
||||||
|
);
|
||||||
|
-- create "s_personal_daten" table
|
||||||
|
CREATE TABLE "s_personal_daten" (
|
||||||
|
"personal_nummer" integer NOT NULL,
|
||||||
|
"aktiv_beschaeftigt" boolean NULL,
|
||||||
|
"vorname" character varying(255) NULL,
|
||||||
|
"nachname" character varying(255) NULL,
|
||||||
|
"geburtsdatum" date NULL,
|
||||||
|
"plz" character varying(255) NULL,
|
||||||
|
"adresse" character varying(255) NULL,
|
||||||
|
"geschlecht" smallint NULL,
|
||||||
|
"card_uid" character varying(255) NULL,
|
||||||
|
"hauptbeschaeftigungs_ort" smallint NULL,
|
||||||
|
"arbeitszeit_per_tag" real NULL,
|
||||||
|
"arbeitszeit_min_start" time NULL,
|
||||||
|
"arbeitszeit_max_ende" time NULL,
|
||||||
|
"vorgesetzter_pers_nr" integer NULL,
|
||||||
|
PRIMARY KEY ("personal_nummer")
|
||||||
|
);
|
||||||
|
-- set comment to column: "geschlecht" on table: "s_personal_daten"
|
||||||
|
COMMENT ON COLUMN "s_personal_daten"."geschlecht" IS '1==weiblich, 2==maennlich, 3==divers';
|
||||||
|
-- drop "personal_daten" table
|
||||||
|
DROP TABLE "personal_daten";
|
||||||
21
migrations/20250901201710_triggers_extension.sql
Normal file
21
migrations/20250901201710_triggers_extension.sql
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-- update Funktion für pass_hash
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION update_zuletzt_geandert()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
-- Nur wenn hash geändert wurde
|
||||||
|
IF NEW.pass_hash IS DISTINCT FROM OLD.pass_hash THEN
|
||||||
|
NEW.zuletzt_geandert = now();
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER pass_hash_update
|
||||||
|
BEFORE UPDATE ON user_password
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_zuletzt_geandert();
|
||||||
|
|
||||||
|
-- Adds crypto extension
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
6
migrations/atlas.sum
Normal file
6
migrations/atlas.sum
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
h1:M1O+1WNf/zb6bwiQPExxUhhXL9S4TtZ4qAsuRr0/Zq4=
|
||||||
|
20250901201159_initial.down.sql h1:BkpujZk5zDCVVoroqrZlXgVR0nvT5Sbzye6aR5e6Z5w=
|
||||||
|
20250901201159_initial.up.sql h1:SAruU753YcQ0oFa3Ii6ylzesLulAKD1j74zDvqv3BDQ=
|
||||||
|
20250901201250_control_tables.down.sql h1:4jA+wm0/Ag86KdkKPZfnADsAlOQl1FYIDX8pdfsSYlA=
|
||||||
|
20250901201250_control_tables.up.sql h1:IGDQ9nT39D12buAi0SUauygXH2ZrCh/YNsZGtk9ztWc=
|
||||||
|
20250901201710_triggers_extension.sql h1:2Oki9mr3nJBE/supbY9HIr+wp4XJT76a38JTByjnHf0=
|
||||||
Reference in New Issue
Block a user