feat(hrworks): Abwesenheiten taeglich aus HRworks uebernehmen

Urlaub, Krankheit, Elternzeit und Feiertage stehen in HRworks. Pulse holt
sie einmal taeglich und bucht sie auf das nicht abrechenbare Projekt
"Abwesenheiten". Nach HRworks geht nichts zurueck, es wird nur gelesen.

Die Stunden rechnet HRworks selbst: available-working-hours liefert je
Person und Tag das Soll und die verfuegbaren Stunden, die Differenz sind
die Abwesenheitsstunden. Damit stimmen Teilzeit und halbe Tage ohne
eigenen Kalender. relatedEvents nennt den Auslöser; Vorrang hat der
Feiertag, dann Krankheit, dann Abwesenheit.

Abgesprochene Regeln: nur genehmigte Abwesenheiten (validatedOk), bei
Krankmeldungen auch offene Bescheinigungen; nur bis heute buchen, der
Rest waechst taeglich nach; halbe Tage feste 4 Stunden; jeder aktive
Mitarbeiter wird dem Projekt zugewiesen, auch neue.

Jede Buchung traegt hrworks_ref = "<Nummer>@<Tag>" (unique). Ein zweiter
Lauf aendert nichts, Stornos und Verschiebungen verschwinden im naechsten
Lauf, DELETE /api/hrworks/entries entfernt genau diese Buchungen.

Nicht abrechenbare Projekte brauchen keinen Budgettopf mehr. Ein Topf
traegt Volumen, Laufzeit und Satz - das hat nur bei Billable und
Festpreis Sinn. Am Abwesenheitsprojekt war er nur ein Ablaufdatum, das
irgendwann Buchungen blockiert haette.

Taeglicher Lauf ueber systemd (perinco-pulse-hrworks.timer, 5:30 Uhr
Berliner Zeit, Persistent). Bedienung unter Einstellungen ->
Abwesenheiten (HRworks) mit Verbindungstest und Probelauf; der geheime
Schluessel liegt AES-verschluesselt in der Datenbank.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
schakal00783
2026-09-21 14:50:54 +02:00
co-authored by Claude Opus 5
parent 994f39daff
commit 532b15ce99
18 changed files with 1236 additions and 6 deletions
+24
View File
@@ -0,0 +1,24 @@
[Unit]
Description=perinco Pulse - Abwesenheiten aus HRworks abgleichen
After=network-online.target mariadb.service
Wants=network-online.target
[Service]
Type=oneshot
User=pulse
Group=pulse
WorkingDirectory=/var/www/pulse/server
EnvironmentFile=/var/www/pulse/server/.env
# Wie der Webdienst: "heute" und Monatsgrenzen gelten in Berlin.
Environment=TZ=Europe/Berlin
Environment=NODE_ENV=production
ExecStart=/usr/bin/node src/jobs/hrworks-sync.js
# Ein hoher Wert waere hier falsch: laeuft HRworks nicht, soll der Lauf
# abbrechen und es morgen erneut versuchen, statt haengen zu bleiben.
TimeoutStartSec=600
MemoryMax=512M
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/www/pulse/server
+15
View File
@@ -0,0 +1,15 @@
[Unit]
Description=Taeglicher Abgleich der Abwesenheiten aus HRworks
[Timer]
# Frueh am Morgen, bevor jemand seine Zeiten ansieht. RandomizedDelay
# verteilt die Last, Persistent holt einen verpassten Lauf nach (Neustart).
# Ortszeit im Kalenderausdruck - der Server laeuft auf UTC, der Lauf soll
# aber morgens in Berlin liegen, auch nach der Zeitumstellung.
OnCalendar=*-*-* 05:30:00 Europe/Berlin
RandomizedDelaySec=300
Persistent=true
Unit=perinco-pulse-hrworks.service
[Install]
WantedBy=timers.target