# Zeiterfassung - App-Dokumentation ## Ueberblick Diese Canvas App dient zur einfachen Zeiterfassung fuer einen angemeldeten Benutzer. Die App besteht aktuell aus genau einer Startseite (`ZeiterfassungNeu`) und zeigt den aktuellen Status, die laufende Sitzung sowie Tages- und Monatssummen an. Benutzer koennen sich ueber **Kommen** einstempeln und ueber **Gehen** ausstempeln. Die App arbeitet mit einer Mischung aus: - App-weiten Hilfsfunktionen in `App.pa.yaml` - lokalem UI-State in Variablen - zwischengespeicherten Collections fuer Tages- und Monatsdaten - direktem Schreiben und Lesen aus der Datenquelle `Time Tracking Entry` ## Dateien | Datei | Zweck | |---|---| | `App.pa.yaml` | App-Startlogik, globale Variablen, Hilfsfunktionen, Startscreen | | `ZeiterfassungNeu.pa.yaml` | Einziger Screen mit UI, Datenabruf, Ein- und Ausstempeln | ## Startverhalten Beim Start der App werden in `App.OnStart` mehrere Variablen initialisiert: - `varCurrentUserEmail`: E-Mail des aktuellen Benutzers in Kleinbuchstaben - `varSelectedDate`: standardmaessig das heutige Datum - `varIsAdminUser`: Admin-Flag - `varIsLoading`: Sperrt UI waehrend laufender Datenoperationen - `varCurrentOpenEntry`: aktuell offener Zeiteintrag - `varLunchSelected` / `varDinnerSelected`: Status der Verpflegungsoptionen - `varCurrentDayMinutes`, `varCurrentMonthMinutes`, `varCurrentSessionMinutes`: berechnete Kennzahlen Zusaetzlich wird geprueft, ob der aktuelle Benutzer Mitglied einer festen Office-365-Gruppe ist. Ist das der Fall, wird `varIsAdminUser` auf `true` gesetzt. ## Datenquellen und Konnektoren ### `Time Tracking Entry` Die fachliche Hauptdatenquelle ist `Time Tracking Entry`. Darin werden Zeiteintraege gelesen und geschrieben. Verwendete Felder sind unter anderem: - `mitarbeiter` - `aktivitaetsdatum` - `aktivitaetsdatumzeit` - `astart` - `Kommen` - `Gehen` - `checkout` - `zeitrecid` - `mittagessen` - `Mittagessen` - `Abendessen` - `Tagestotal` - `Monatstotal` Die App schreibt sowohl deutsch benannte als auch englisch benannte Essensfelder (`mittagessen` / `Mittagessen`). Das deutet auf ein historisch gewachsenes oder technisch bedingtes Mapping der Datenquelle hin. ### `Office365Groups` Der Konnektor `Office365Groups` wird fuer die Adminpruefung verwendet. Ueber `ListGroupMembers(...)` wird geprueft, ob der aktuelle Benutzer in einer fest hinterlegten Gruppe enthalten ist. ## Globale Hilfsfunktionen In `App.Formulas` sind mehrere wiederverwendbare Funktionen definiert: - `FormatMinutes(totalMinutes)`: Wandelt Minuten in `HH:mm` um - `WorkMinutes(startDt, endDt)`: Berechnet gearbeitete Minuten und verhindert negative Werte - `FormatBalance(totalHours)`: Formatiert Stundensalden mit Vorzeichen - `EntryDurationHours(startDt, endDt, breakMinutes)`: Rechnet einen Eintrag in Stunden um - `StatusColor(statusText)`: Liefert eine Farbzuordnung fuer Statuswerte Zusaetzlich sind zwei Theme-Objekte vorhanden: - `AppTheme` - `AppTheme2` Diese kapseln zentrale Farben fuer Oberflaeche, Text, Erfolg, Warnung und Fehler. ## Screen `ZeiterfassungNeu` ### Zweck Der Screen ist die Hauptoberflaeche fuer die taegliche Zeiterfassung. Beim Oeffnen wird automatisch `btnReloadData` ausgefuehrt, wodurch die aktuellen Daten geladen und die Anzeige initialisiert wird. ### Sichtbare Bereiche #### 1. Kopfbereich Der Header zeigt: - den Titel **Zeiterfassung** - das aktuell gewaehlte Datum - den Status **Nicht eingestempelt** oder **Eingestempelt** Die Statusfarbe wechselt zwischen Fehler-/Warnfarbton und Erfolgsfarbe, abhaengig davon, ob ein offener Eintrag existiert. #### 2. Live-Zusammenfassung Dieser Bereich zeigt: - die aktuelle Uhrzeit - die aktuelle Sitzungsdauer Die Sitzungsdauer wird aus `varCurrentSessionMinutes` berechnet. Ein Timer aktualisiert diese Anzeige laufend. #### 3. Aktionen Es gibt zwei Hauptaktionen: - `btnKommen` - `btnGehen` **Kommen** Beim Einstempeln passiert Folgendes: 1. Pruefung, ob bereits ein offener Eintrag existiert 2. Setzen des Ladezustands 3. Erzeugen einer neuen `zeitrecid` per `GUID()` 4. `Patch()` eines neuen Datensatzes in `Time Tracking Entry` 5. Speichern von Benutzer, Datum, Startzeit und Verpflegungsstatus 6. `Refresh()` der Datenquelle 7. erneutes Laden der lokalen Daten ueber `btnReloadData` **Gehen** Beim Ausstempeln passiert Folgendes: 1. Pruefung, ob ein offener Eintrag vorhanden ist 2. Berechnung der aktuellen Sitzungsdauer 3. Neuberechnung von Tages- und Monatssumme ohne Doppelzaehlung des offenen Eintrags 4. `Patch()` des offenen Datensatzes mit Endzeit und Summen 5. `Refresh()` der Datenquelle 6. erneutes Laden der lokalen Daten ueber `btnReloadData` #### 4. Verpflegung Es gibt zwei Checkboxen: - `Mittagessen` - `Abendessen` Die Auswahl wird lokal in `varLunchSelected` und `varDinnerSelected` gehalten und beim Ein- oder Ausstempeln in die Datenquelle geschrieben. #### 5. Summen Es werden zwei Kennzahlen angezeigt: - `Tagestotal` - `Monatstotal` Beide werden aus vorbereiteten Collections berechnet und mit `FormatMinutes(...)` formatiert dargestellt. #### 6. Admin-Button Ein `Admin`-Button ist vorhanden, aber die Navigation ist aktuell auskommentiert: ```text //Navigate(Eintragsverwaltung, ScreenTransition.Fade) ``` Der Button ist nur sichtbar, wenn `varIsAdminUser = true`. ## Datenfluss ### Versteckter Reload-Mechanismus Die App verwendet einen unsichtbaren Button `btnReloadData` als zentrale Ladefunktion. Dessen `OnSelect` ist die wichtigste Stelle fuer das Lesen und Aufbereiten der Daten. Der Ablauf: 1. `Refresh('Time Tracking Entry')` 2. Laden aller Benutzereintraege in `colUserEntries` 3. Filtern des ausgewaehlten Tages nach `colRawTodayEntries` 4. Anreichern zu `colTodayEntries` mit: - `startTime` - `endTime` - `recordId` - `lunchValue` - `dinnerValue` 5. Filtern des aktuellen Monats nach `colRawMonthEntries` 6. Anreichern zu `colMonthEntries` 7. Ermitteln des offenen Eintrags in `varCurrentOpenEntry` 8. Berechnen der aktuellen Kennzahlen und Ruecksetzen der Checkboxen ### Live-Aktualisierung Ein unsichtbarer Timer `timRefresh` laeuft mit einer Dauer von 1000 ms und aktualisiert: - `varCurrentSessionMinutes` - `varCurrentDayMinutes` - `varCurrentMonthMinutes` Dadurch bleibt die Anzeige waehrend einer laufenden Sitzung aktuell, ohne die Datenquelle sekundenweise neu zu laden. ## Verwendete Collections | Collection | Inhalt | |---|---| | `colUserEntries` | Alle Eintraege des aktuellen Benutzers | | `colRawTodayEntries` | Rohe Tagesdaten vor Anreicherung | | `colTodayEntries` | Tagesdaten mit berechneten Hilfsfeldern | | `colRawMonthEntries` | Rohe Monatsdaten vor Anreicherung | | `colMonthEntries` | Monatsdaten mit berechneten Hilfsfeldern | ## Verwendete Variablen | Variable | Bedeutung | |---|---| | `varCurrentUserEmail` | E-Mail des aktuellen Benutzers | | `varSelectedDate` | aktuell betrachtetes Datum | | `varIsAdminUser` | steuert die Sichtbarkeit von Admin-Funktionen | | `varIsLoading` | sperrt Controls waehrend Datenoperationen | | `varCurrentOpenEntry` | aktuell offener Zeiteintrag | | `varLunchSelected` | Mittagessen aktiviert | | `varDinnerSelected` | Abendessen aktiviert | | `varCurrentSessionMinutes` | Dauer der laufenden Sitzung | | `varCurrentDayMinutes` | Summe fuer den aktuellen Tag | | `varCurrentMonthMinutes` | Summe fuer den aktuellen Monat | | `varNewDayMinutes` | Hilfsvariable beim Ausstempeln | | `varNewMonthMinutes` | Hilfsvariable beim Ausstempeln | ## Responsive Verhalten Die App nutzt `AutoLayout`-Container. Mehrere Bereiche schalten bei schmaler Breite (`App.Width < 600`) von horizontalem auf vertikales Layout um. Dadurch ist die Ansicht fuer kleinere Displays vorbereitet. ## Aktuelle Einschraenkungen und Auffaelligkeiten - Die App hat derzeit nur einen produktiv genutzten Screen. - Der Admin-Button ist sichtbar, aber funktional noch nicht verdrahtet. - In `App.OnStart` werden einige Variablen mehrfach gesetzt. Das ist funktional unkritisch, aber pflegeintensiver. - Die Datenquelle verwendet teilweise doppelte Feldkonzepte fuer Verpflegung (`mittagessen` und `Mittagessen`). ## Kurzfazit Die App ist als kompakte Single-Screen-Zeiterfassung umgesetzt. Der Kern besteht aus: - Einstempeln und Ausstempeln - Live-Anzeige der aktuellen Sitzung - Berechnung von Tages- und Monatssummen - optional sichtbarer Admin-Einstieg Der technische Schwerpunkt liegt auf lokal vorbereiteten Collections und einem zentralen Reload-Mechanismus fuer konsistente Anzeige nach jeder Aenderung.