102 lines
3.9 KiB
Markdown
102 lines
3.9 KiB
Markdown
# Copilot Plan: Attendance PDF Generator
|
||
|
||
## Ziel
|
||
Kombiniertes Python-CLI-Tool, das Anwesenheitsdaten aus einer Excel-Datei liest
|
||
und für jeden Teilnehmer eine ausgefüllte PDF-Datei erzeugt.
|
||
|
||
## Architektur
|
||
|
||
```
|
||
generate.py # Click CLI entry point
|
||
config.json # Konfiguration (antragsnummer, ort, month_mapping, ...)
|
||
schema.json # JSON-Schema der Konfiguration (Dokumentation)
|
||
requirements.txt # openpyxl, pypdf, click
|
||
requirements-dev.txt # + pytest
|
||
src/
|
||
__init__.py
|
||
exceptions.py # Custom Exception-Hierarchie
|
||
models.py # Datenklassen: Person, AttendanceDate, MonthlyAttendance
|
||
config_loader.py # config.json laden & validieren
|
||
excel_reader.py # Excel → MonthlyAttendance-Objekte
|
||
pdf_filler.py # MonthlyAttendance → ausgefüllte PDF
|
||
validators.py # Pre-Generation Validierung + Konsolenvorschau
|
||
template/ # PDF-Template (sab.pdf, wird separat bereitgestellt)
|
||
output/ # Ausgabeverzeichnis für generierte PDFs
|
||
tests/
|
||
__init__.py
|
||
test_excel_reader.py
|
||
test_pdf_filler.py
|
||
test_validators.py
|
||
```
|
||
|
||
## Datenfluss
|
||
Excel-Datei → excel_reader → MonthlyAttendance → pdf_filler → PDF-Datei
|
||
|
||
## Entwurfsentscheidungen
|
||
- `plan.N` = immer `"6"` (mind. 6h), unabhängig von tatsächlichen Stunden
|
||
- Sheet-Auswahl: manuell via `--month <name>` (z.B. `--month Feb`)
|
||
- Output-Benennung: `(n) Nachname, Vorname.pdf` (n = lfd. Nummer aus Spalte A)
|
||
- `pauschale_5.N` = Dropdown-Wert `"1"` (= 8,60 €) wenn anwesend (X), sonst `"0"`
|
||
- PDF-Template liegt in `./template/sab.pdf`
|
||
- PDF-Felder für Ort und Datum: `unterschrift.ort` / `unterschrift.datum`
|
||
|
||
## Excel-Struktur
|
||
- Spalte A (Index 0): lfd. Nummer
|
||
- Spalte B (Index 1): Name (Format: "Nachname, Vorname")
|
||
- Spalten J–AN (Index 9–39): Tageswerte (Tag 1–31)
|
||
- Numerischer Wert → anwesend (X), Wert = Ist-Stunden
|
||
- "K" → Krank
|
||
- "KK" → Kindkrank
|
||
- "F" → unentschuldigtes Fehlen
|
||
- "E" → entschuldigtes Fehlen
|
||
- "P" → Praktikum
|
||
- "U" → Urlaub
|
||
- "V" → Vorstellungsgespräch
|
||
- "A" → aus Projekt ausgeschieden
|
||
- Leer → Zeile überspringen
|
||
|
||
## PDF-Feld-Mapping (pro Zeile N, max 23 Zeilen)
|
||
| Excel-Zelle | datum.N | anwesend.N | ist.N | plan.N | pauschale_5.N |
|
||
|---|---|---|---|---|---|
|
||
| Numerisch | DD.MM.YYYY | X | Wert (dt. Format) | "6" | "1" |
|
||
| "K"/"KK"/etc| DD.MM.YYYY | Code | leer | leer | "0" |
|
||
| Leer | (überspringen) | — | — | — | — |
|
||
|
||
---
|
||
|
||
## Windows-Installer (Inno Setup)
|
||
|
||
### Ziel
|
||
Installer-EXE erstellen, die:
|
||
- Von einem Windows SMB-Share aus gestartet werden kann (self-contained .exe)
|
||
- Das Programm lokal unter `%ProgramFiles%\AnwesenheitPDF\` installiert
|
||
- Einen Startmenü-Eintrag anlegt (optional: Desktop-Verknüpfung)
|
||
- Einen Uninstaller registriert (Programme und Features)
|
||
|
||
### Tool: Inno Setup 6
|
||
- Free, open-source, weit verbreitet
|
||
- Erzeugt eine einzelne selbstextrahierende .exe (ideal für SMB-Share)
|
||
- Unterstützt German.isl (deutschsprachiger Wizard)
|
||
- ISCC.exe (Compiler) muss auf Build-Maschine installiert sein
|
||
- Installation: `winget install --id JRSoftware.InnoSetup -e -s winget -i`
|
||
|
||
### Dateien
|
||
- `installer\AnwesenheitPDF.iss` — Inno Setup Script
|
||
- `build.bat` — um Installer-Schritt erweitert (ruft ISCC auf)
|
||
- Ausgabe: `dist\AnwesenheitPDF-Setup-x.y.z.exe`
|
||
|
||
### Ablauf build.bat (neu: Schritt 4)
|
||
1. pip install
|
||
2. update_version.py (liest Version aus config.json)
|
||
3. PyInstaller → dist\AnwesenheitPDF\
|
||
4. Version aus config.json extrahieren → ISCC aufrufen → dist\AnwesenheitPDF-Setup-x.y.z.exe
|
||
|
||
### Install-Ziel
|
||
- `{autopf}\AnwesenheitPDF\` (= Program Files, UAC-geschützt)
|
||
- Requires admin (PrivilegesRequired=admin)
|
||
- Startmenü: `{group}\AnwesenheitPDF`
|
||
|
||
## Release Notes
|
||
- Aktuelle Versionsnummer aus config.json bestaetigen.
|
||
- Release-Notes-Dokument im Projekt-Root anlegen.
|
||
- Release-Notes-Datei zusaetzlich zum Installer in `update_check_path` kopieren. |