From f21ce9a3c3598c6e8e0f463fdf203ffc5012b3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Tr=C3=B6ger?= Date: Tue, 24 Feb 2026 20:05:08 +0100 Subject: [PATCH] fixed: pause time calculation from work instead of presence time --- Backend/models/booking_test.go | 215 +++++++++++++++++++++++++++++++++ Backend/models/workDay.go | 3 +- Backend/models/workDay_test.go | 102 +++++++++++++++- Readme.md | 91 ++++++++++++++ 4 files changed, 404 insertions(+), 7 deletions(-) diff --git a/Backend/models/booking_test.go b/Backend/models/booking_test.go index d344e40..48f44f9 100644 --- a/Backend/models/booking_test.go +++ b/Backend/models/booking_test.go @@ -45,3 +45,218 @@ var testBookings10hrs = []models.Booking{{ Timestamp: time.Date(2025, 01, 01, 18, 0, 0, 0, time.UTC), BookingType: testBookingType, }} + +var testBookings6hrsBreak30min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 14, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }} + +var testBookings610hrsBreak30min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 14, 40, 0, 0, time.UTC), + BookingType: testBookingType, + }} + +var testBookings9hrsBreak30min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 17, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }} + +var testBookings930hrs = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 17, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }} + +var testBookings910hrsBreak30min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 17, 40, 0, 0, time.UTC), + BookingType: testBookingType, + }, +} + +var testBookings910hrsBreak35min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 35, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 17, 45, 0, 0, time.UTC), + BookingType: testBookingType, + }, +} + +var testBookings945hrs = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 17, 45, 0, 0, time.UTC), + BookingType: testBookingType, + }, +} + +var testBookings10hrsBreak45min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 45, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 18, 00, 0, 0, time.UTC), + BookingType: testBookingType, + }, +} + +var testBookings1030hrsBreak45min = []models.Booking{ + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 8, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 9, 0, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 1, + Timestamp: time.Date(2025, 01, 01, 9, 45, 0, 0, time.UTC), + BookingType: testBookingType, + }, + { + CardUID: "aaaa-aaaa", + CheckInOut: 2, + Timestamp: time.Date(2025, 01, 01, 18, 30, 0, 0, time.UTC), + BookingType: testBookingType, + }, +} diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index 974696e..7a6e6e3 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -116,7 +116,8 @@ func correctWorkPause(workIn, pauseIn time.Duration) (work, pause time.Duration) } var diff time.Duration - if workIn <= (9*time.Hour) && pauseIn < 30*time.Minute { + + if (workIn+pauseIn) <= (9*time.Hour+30*time.Minute) && pauseIn <= 30*time.Minute { diff = 30*time.Minute - pauseIn } else if pauseIn < 45*time.Minute { diff = 45*time.Minute - pauseIn diff --git a/Backend/models/workDay_test.go b/Backend/models/workDay_test.go index a3fe7be..7159ef9 100644 --- a/Backend/models/workDay_test.go +++ b/Backend/models/workDay_test.go @@ -30,18 +30,63 @@ func TestWorkdayWorktimeDay(t *testing.T) { }{ { testName: "Bookings6hrs", - bookings: testBookings6hrs, - expectedTime: time.Hour * 6, + bookings: testBookings6hrs, //work 6h + expectedTime: time.Hour * 6, //pause 0 }, { testName: "Bookings8hrs", - bookings: testBookings8hrs, - expectedTime: time.Hour*7 + time.Minute*30, + bookings: testBookings8hrs, //work 8 pause 0 + expectedTime: time.Hour*7 + time.Minute*30, //pause 30 --> corrected }, { testName: "Bookings10hrs", - bookings: testBookings10hrs, - expectedTime: time.Hour*9 + time.Minute*15, + bookings: testBookings10hrs, //work 10 pause 0 + expectedTime: time.Hour*9 + time.Minute*15, //pause 45 --> corrected + }, + { + testName: "Booking 6h with 30 min Break", + bookings: testBookings6hrsBreak30min, //work 6 pause 30 + expectedTime: time.Hour * 6, //pause 30 --> bc real pause + }, + { + testName: "Booking 6h 10min with 30 min Break", + bookings: testBookings610hrsBreak30min, //work 6 10 pause 30 + expectedTime: time.Hour*6 + time.Minute*10, //pause 30 --> real pause + }, + { + testName: "Booking 9h with 30 min Break", + bookings: testBookings9hrsBreak30min, //work 9 pause 30 + expectedTime: time.Hour * 9, //pause 30 --> real pause + }, + { + testName: "Booking 9h 30min", + bookings: testBookings930hrs, //work 9 30 pause 0 + expectedTime: time.Hour * 9, //pause 30 --> corrected + }, + { + testName: "Booking 9h 40min with 30min Break", + bookings: testBookings910hrsBreak30min, //work 9 10 pause 30 + expectedTime: time.Hour*8 + time.Minute*55, //pause 45 --> real + corrected + }, + { + testName: "Booking 9h 40min with 35min Break", + bookings: testBookings910hrsBreak35min, //work 9 10 pause 35 + expectedTime: time.Hour * 9, //pause 45 --> real + corrected + }, + { + testName: "Booking 9h 45min", + bookings: testBookings945hrs, //work 9 45 pause 0 + expectedTime: time.Hour * 9, //pause 45 --> corrected + }, + { + testName: "Booking 10h Break 45min", + bookings: testBookings10hrsBreak45min, //work 9 15 pause 45 + expectedTime: time.Hour*9 + time.Minute*15, //pause 45 --> real + }, + { + testName: "Booking 10h 30min Break 45min", + bookings: testBookings1030hrsBreak45min, //work 9 45 pause 45 + expectedTime: time.Hour*9 + time.Minute*45, //pause 45 --> real }, } @@ -113,6 +158,51 @@ func TestWorkdayPausetimeDay(t *testing.T) { bookings: testBookings10hrs, expectedTime: time.Minute * 45, }, + { + testName: "Booking 6h with 30 min Break", + bookings: testBookings6hrsBreak30min, //work 6 pause 30 + expectedTime: time.Minute * 30, //pause 30 --> bc real pause + }, + { + testName: "Booking 6h 10min with 30 min Break", + bookings: testBookings610hrsBreak30min, //work 6 10 pause 30 + expectedTime: time.Minute * 30, //pause 30 --> real pause + }, + { + testName: "Booking 9h with 30 min Break", + bookings: testBookings9hrsBreak30min, //work 9 pause 30 + expectedTime: time.Minute * 30, //pause 30 --> real pause + }, + { + testName: "Booking 9h 30min", + bookings: testBookings930hrs, //work 9 30 pause 0 + expectedTime: time.Minute * 30, //pause 30 --> corrected + }, + { + testName: "Booking 9h 40min with 30min Break", + bookings: testBookings910hrsBreak30min, //work 9 10 pause 30 + expectedTime: time.Minute * 45, //pause 45 --> real + corrected + }, + { + testName: "Booking 9h 40min with 35min Break", + bookings: testBookings910hrsBreak35min, //work 9 10 pause 35 + expectedTime: time.Minute * 45, //pause 45 --> real + corrected + }, + { + testName: "Booking 9h 45min", + bookings: testBookings945hrs, //work 9 45 pause 0 + expectedTime: time.Minute * 45, //pause 45 --> corrected + }, + { + testName: "Booking 10h Break 45min", + bookings: testBookings10hrsBreak45min, //work 9 15 pause 45 + expectedTime: time.Minute * 45, //pause 45 --> real + }, + { + testName: "Booking 10h 30min Break 45min", + bookings: testBookings1030hrsBreak45min, //work 9 45 pause 45 + expectedTime: time.Minute * 45, //pause 45 --> real + }, } for _, tc := range testCases { diff --git a/Readme.md b/Readme.md index eb15764..5d8e1c7 100644 --- a/Readme.md +++ b/Readme.md @@ -50,9 +50,100 @@ cd arbeitszeitmessung - `BACKUP_FOLDER` Pfad für DB Backup Datein - `LOG_PATH` Pfad für Audit Logs +## Administration: + +### Nutzer erstellen: + +Nutzerdaten erstellen: + +```sql +INSERT INTO "s_personal_daten" + ( + "personal_nummer", + "vorname", + "nachname", + "card_uid", + "geburtsdatum", + "geschlecht", + "adresse", + "plz", + "hauptbeschaeftigungs_ort", + "aktiv_beschaeftigt", + "vorgesetzter_pers_nr", + "arbeitszeit_min_start", + "arbeitszeit_max_ende", + "arbeitszeit_per_tag", + "arbeitszeit_per_woche", + ) +VALUES ( + 1, + 'Max', + 'Mustermann', + 'acde-edca', + '2003-02-01', + 1, + 'Musterstr. 42', + '00001', + 1, + true, + 123, + '07:00:00', + '20:00:00', + 8, + 40 + ); +``` + +Nutzerpasswort generieren (kann auch später als Passwort reset genutzt werden): + +```sql +INSERT INTO "user_password" + ("personal_nummer", "pass_hash") +VALUES (123, crypt('password', gen_salt('bf'))); +``` + +### Buchungstypen erstellen: + +Ohne definierte Anwesenheits und Abwesenheitstypen funktioniert die Anwendung nicht! + +Anwesenheiten: + +```sql +INSERT INTO "s_anwesenheit_typen" + ("anwesenheit_id", "anwesenheit_name") +VALUES (1, 'Büro'); +``` + +Abwesenheiten: + +```sql +INSERT INTO "s_abwesenheit_typen" + ("abwesenheit_id", "abwesenheit_name", "arbeitszeit_equivalent") +VALUES (1, 'Urlaub', 100); +``` + +### Feiertage erstellen: + +Die gesetzlichen Feiertage für Deutschland/Sachsen werden automatisch mit der Route `auto/feiertage` für das aktuelle Kalenderjahr erzeugt. Um weitere Unternehmensspezifische Feiertage (z.B. 24.12. oder 31.12.) mit in die Liste der Feiertage aufzunehmen, müssen diese manuell erstellt werden. + +```sql +INSERT INTO "s_feiertage" + ("datum", "name", "arbeitszeit_equivalent", "wiederholen") +VALUES ('2026-12-24', 'Helligabend', 50, 1); +``` + +Wenn `wiederholen` == 1 wird der Feiertag automatisch beim Aufruf von `auto/feiertage` mit ins nächste Jahr (am selben Datum) übernommen. + +Das Feld `arbeitszeit_equivalent` `arbeitszeit_equivalent` ist die prozentuelle Zeit am Tag welche durch diesen Eintrag eingenommen wird. (dies gilt auch für die [Buchungstypen](#buchungstypen-erstellen)) + +Alle weiteren Tabellen sollte ausschließlich über die Weboberfläche oder per API befüllt werden. + +--- + # Filestrukture ``` + ├── Backend (Webserver) │   ├── doc (Templates for Document Creator --> typst used to create PDF Reports) │   │   ├── static