9.7 KiB
Ziel
Eine Python + Streamlit App für Windows, die aus einer Input-Excel-Datei (ein Sheet pro Monat mit Mitarbeiterdaten) und einem PDF-Template pro Mitarbeiter eine PDF-Datei generiert (eine Seite pro Monat, befüllt mit dessen Daten).
Ansatz: openpyxl für Input-Parsing + PyMuPDF (fitz) für PDF-Generierung + Streamlit-UI.
Hintergrund: Das ursprüngliche Excel-Template war teilweise schreibgeschützt und konnte nicht mit openpyxl befüllt werden. Daher wurde das Template als PDF exportiert. Im PDF wurden alle zu befüllenden Textstellen mit einem Platzhalter im Format
{Feldname}_Fieldmarkiert (z. B.Antragsnummer_Field,Name_Field). Die App sucht nach diesen_Field-Markern und ersetzt sie durch die echten Daten.
Aufgabe
Erstelle eine Windows App in dessen Oberfläche aus folgenden Bestandteilen aufgebaut ist:
- mittels einem DropDown-Menü kann eine Datei aus dem inputfolder gewählt werden
- mittels einem DropDown-Menü kann ein PDF-Template aus dem Templatefolder gewählt werden
- ein Button um den Vorgang zu starten
Die Funktion der App besteht darin, das Template-PDF mit Daten aus dem Input-File zu befüllen. Im Inputfile ist für alle Monate eines Jahres eine Liste aller Mitarbeitenden und in den Spalten alle Daten zur Befüllung des Templates.
Aufbau Input Datei
- In der Input Datei ist für jeden Monat eines Jahres ein Sheet gespeichert.
- In jedem Sheet befindet sich eine Tabelle (felder speichern in Input Schema json) mit Mitarbeitenden.
- Für jeden Mitarbeitenden wird ein PDF erzeugt, das für jeden Monat eine Seite enthält, befüllt mit den Daten des Mitarbeiters für diesen Monat.
Aufbau PDF-Template
- Das PDF-Template ist eine einseitige PDF-Datei, generiert aus der ursprünglichen XLSX-Vorlage.
- Jede zu befüllende Textstelle enthält einen Platzhalter: den Feldnamen gefolgt von
_Field(z. B.Antragsnummer_Field,Name_Field,Stellenanteil in %_Field, …). - Die App sucht im PDF nach allen
_Field-Texten, ermittelt deren Position und Schriftgröße, und ersetzt sie durch die tatsächlichen Datenwerte.
README
In der README.md ist ein kleine Doku wie das Programm zu benutzen ist und welche Konfigurationsparameter es gibt.
Phasen-Plan
Phase 1: Projekt-Grundgerüst & Konfiguration
requirements.txtbefüllen —streamlit,openpyxl,PyMuPDFconfig/settings.inibefüllen — Pfade, Standardwerte- Abschnitte:
[paths](input_dir, template_dir, output_dir),[output](filename_pattern →.pdf)
- Abschnitte:
config/input-fields.jsonSchema definieren — Spalten der Input-Tabelle mit ihren exakten Überschriften- JSON-Array mit
column(Spaltenbuchstabe),field_name(exakte Überschrift aus der Excel-Tabelle),type(string|number|date),required(true|false)
- JSON-Array mit
config/output-fields.jsonMapping definieren — Welche Input-Felder in das PDF geschrieben werden- JSON-Array mit
source_field(exakte Spaltenüberschrift aus der Input-Tabelle),format(optional, z. B. "dd.mm.yyyy") - Der Platzhalter im PDF ist immer
{source_field}_Field– kein explizitestarget_cellmehr nötig
- JSON-Array mit
Phase 2: Core-Module (src/)
src/__init__.py+src/models.py— DatenklassenEmployeeRecord: name, vorname, nachname, antragsnummer, qualifikation, funktion, taetigkeit, stellenanteil, monat, jahr, … (Felder aus input-fields.json)AppConfig: geladene settings.ini + input/output-schemas
src/config.py— Konfigurations-Loaderload_settings(): liestconfig/settings.inimitconfigparserload_input_schema(): liestconfig/input-fields.jsonload_output_mapping(): liestconfig/output-fields.jsonget_available_input_files(): listet.xlsx-Dateien ininput/get_available_templates(): listet.pdf-Dateien intemplate/
src/parser.py— Input-Datei einlesen (unverändert: openpyxl für XLSX-Input)parse_input_file(filepath, schema): öffnet Workbook, iteriert über alle Sheets (Monate)- Extrahiert Monat/Jahr aus Sheet-Namen oder Sheet-Inhalt
- Für jedes Sheet: liest Zeilen anhand des Schemas, erzeugt
EmployeeRecord-Liste - Rückgabe:
list[EmployeeRecord]
Phase 3: Writer & Validierung (PDF-basiert)
src/writer.py— PDF-Output generieren (NEU: PyMuPDF)generate_activity_reports(employee_records, template_path, mapping, config):- Pre-Scan: Öffnet das Template-PDF einmal und sucht nach allen
_Field-Platzhaltern, ermittelt deren Position (bounding box) und Schriftgröße - Gruppiert Records nach Mitarbeiter
- Für jeden Mitarbeiter:
- Erstellt ein neues PDF
- Für jeden Monats-Record: fügt eine Kopie der Template-Seite ein
- Ersetzt alle
_Field-Platzhalter durch die tatsächlichen Daten (redact + insert_text) - Speichert als
{nachname}_{vorname}_Tätigkeitsnachweis.pdfinoutput/
- Pre-Scan: Öffnet das Template-PDF einmal und sucht nach allen
src/validator.py— Eingabevalidierung (angepasst für PDF)validate_input_file(filepath, schema): unverändert (prüft XLSX-Input)validate_template(template_path, mapping): prüft ob alle_Field-Platzhalter im PDF gefunden werden
Phase 4: Streamlit UI
app.py— Streamlit-Oberfläche (angepasst für PDF-Templates)- Layout:
- Titel + Beschreibung
st.selectboxfür Input-Datei (ausinput/-Folder)- Sofort bei Auswahl: Validierung + Parsing der Datei
- Anzeige: Anzahl gefundener Mitarbeiter, Auflistung aller enthaltenen Antragsnummern
st.selectboxfür PDF-Template (austemplate/-Folder)- Sofort bei Auswahl: Validierung des PDF-Templates (Prüfung aller
_Field-Marker) - Anzeige: Anzahl gefundener Platzhalter-Felder
- Sofort bei Auswahl: Validierung des PDF-Templates (Prüfung aller
- Mitarbeiter-Liste (erscheint nach erfolgreicher Input-Validierung)
st.multiselectmit allen gefundenen Mitarbeiternamen, standardmäßig alle vorselektiert
st.button("Tätigkeitsnachweise generieren")
- Bei Button-Click:
- Filtere Employee Records auf selektierte Mitarbeiter
- Generiere PDFs nur für selektierte Mitarbeiter und speichere in
output/ - Zeige Erfolgsmeldung mit Liste der erstellten PDF-Dateien
- Layout:
Phase 5: Start-Skript & Doku
start.bat— Windows Batch-Startdatei (unverändert)README.mdaktualisieren — Vollständige Doku
Relevante Dateien (zu erstellen/ändern)
| Datei | Aktion |
|---|---|
requirements.txt |
PyMuPDF hinzufügen |
config/settings.ini |
filename_pattern auf .pdf ändern |
config/output-fields.json |
target_cell entfernen (wird durch _Field-Marker ersetzt) |
src/writer.py |
Komplett neu: PDF-basierte Generierung mit PyMuPDF |
src/validator.py |
validate_template für PDF anpassen |
src/config.py |
get_available_templates auf .pdf umstellen |
app.py |
Template-Validierung für PDF anpassen |
coldrun.py |
An PDF-Template anpassen |
tests/test_e2e.py |
Tests für PDF-Output anpassen |
.copilot/PLAN.md |
Dieser Plan – aktualisiert |
.copilot/TASKS.md |
Aufgabenliste – aktualisiert |
CHANGELOG.md |
Changelog – wird bei jedem Version-Build erweitert |
Projektstruktur
/
├── .copilot/
│ ├── PLAN.md ← diese Datei
│ └── TASKS.md ← Aufgabenliste
├── input/
│ └── *.xlsx ← Tabelle mit den Input-daten
├── config/
│ ├── settings.ini ← Einstellungen der App
│ ├── input-fields.json ← Schema der Inputdaten-Tabelle
│ └── output-fields.json ← Mapping: Input-Feld → PDF-Platzhalter
├── output/ ← Zielordner für generierte PDF-Dateien
├── template/
│ └── *.pdf ← PDF-Template mit _Field-Platzhaltern
├── src/
│ ├── __init__.py
│ ├── models.py
│ ├── config.py
│ ├── parser.py
│ ├── writer.py ← PDF-basierte Generierung (PyMuPDF)
│ └── validator.py
├── app.py ← Streamlit-App
├── coldrun.py ← CLI Cold-Run
├── start.bat ← Windows batch zum Start der App
├── README.md ← README für Programmbenutzer
├── CHANGELOG.md ← Changelog (wird bei jedem Version-Build erweitert)
└── requirements.txt ← streamlit, openpyxl, PyMuPDF
Versionierung & Changelog
Immer wenn das Signal zum Build einer neuen Version gegeben wird (z. B. „Build Version X.Y“ oder „neue Version bauen“), wird das Changelog-Logfile (CHANGELOG.md im Projekt-Root) um die most recent changes erweitert. Der Eintrag enthält:
- Versionsnummer (z. B.
v1.2.0) - Datum des Builds
- Neue Funktionen (Features)
- Behobene Fehler (Bugfixes)
- Sonstige Änderungen (z. B. Refactoring, Doku-Updates)
Der Changelog wird im Keep a Changelog-Format gepflegt und nach Semantic Versioning (MAJOR.MINOR.PATCH) versioniert.
Wichtig: Der Changelog-Eintrag wird vor dem eigentlichen Build-Vorgang erstellt, sodass die neue Version dokumentiert ist, bevor der Code ausgeliefert wird.
Verifikation
- Input-Datei-Analyse:
2025 JM.xlsxmit openpyxl öffnen, Sheet-Namen prüfen, Spaltenüberschriften validieren - PDF-Template-Analyse:
Tätigkeitsnachweise Stellenförderung.pdfmit PyMuPDF öffnen, alle_Field-Platzhalter suchen → mitoutput-fields.jsonabgleichen - Unit-Test: App mit vorhandener Input-Datei und PDF-Template ausführen, prüfen ob Output-PDFs korrekt befüllt sind
- Edge Cases: Leere Input-Zeilen, fehlende Monate, Mitarbeiter ohne Vorname, Sonderzeichen in Namen, Umlaute im PDF