From b05849e673769614cabe0eaf8c395aaf0b8c0dce Mon Sep 17 00:00:00 2001 From: trnq1ll0 Date: Wed, 10 Jun 2026 16:05:40 +0200 Subject: [PATCH] fix: Stellenanteil in Prozentangabe und jeweiliges Monatsende als Datum eintragen --- config/output-fields.json | 3 ++- src/models.py | 2 +- src/parser.py | 36 +++++++++++++++++++++++++----------- src/writer.py | 16 ++++++++++------ 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/config/output-fields.json b/config/output-fields.json index a10af59..3f6ff4f 100644 --- a/config/output-fields.json +++ b/config/output-fields.json @@ -1,11 +1,12 @@ [ {"source_field": "Antragsnummer", "target_cell": "B3", "format": null}, {"source_field": "Name", "target_cell": "B17", "format": null}, - {"source_field": "Stellenanteil in %", "target_cell": "R17", "format": "%.2f"}, + {"source_field": "Stellenanteil in %", "target_cell": "R17", "format": null}, {"source_field": "Qualifikation", "target_cell": "B21", "format": null}, {"source_field": "Monat (MM.JJ)", "target_cell": "R21", "format": null}, {"source_field": "Funktion", "target_cell": "B25", "format": null}, {"source_field": "Tätigkeit", "target_cell": "B31", "format": null}, {"source_field": "Ort", "target_cell": "B95", "format": null}, + {"source_field": "Ort 2", "target_cell": "B103", "format": null}, {"source_field": "Datum", "target_cell": "J95", "format": null} ] diff --git a/src/models.py b/src/models.py index 5948a9e..6a93bd7 100644 --- a/src/models.py +++ b/src/models.py @@ -11,7 +11,7 @@ class EmployeeRecord: antragsnummer: str qualifikation: str funktion: str - stellenanteil: float + stellenanteil: str monat: str # z. B. "01.2025" taetigkeit: str id: Optional[int] = None diff --git a/src/parser.py b/src/parser.py index 289d58a..a0611b2 100644 --- a/src/parser.py +++ b/src/parser.py @@ -17,16 +17,6 @@ def _to_text(value: Any) -> str: return str(value).strip() -def _to_float(value: Any, field_name: str) -> float: - if value is None or str(value).strip() == "": - return 0.0 - text = str(value).strip().replace(",", ".") - try: - return float(text) - except ValueError: - return 0.0 - - def _to_int_or_none(value: Any) -> Optional[int]: if value is None or str(value).strip() == "": return None @@ -36,6 +26,29 @@ def _to_int_or_none(value: Any) -> Optional[int]: return None +def _to_percent_string(value: Any) -> str: + """Wandelt einen Prozentwert in einen String ohne %-Zeichen um. + + Excel speichert Prozentwerte als Dezimalbruch (50 % = 0.5). + Falls der Rohwert eine Zahl ≤ 1 ist, wird er als Excel-Prozentwert + interpretiert und mit 100 multipliziert. + """ + if value is None or str(value).strip() == "": + return "" + # Falls es bereits ein String mit %-Zeichen ist + if isinstance(value, str): + return value.strip().rstrip("% ") + # Numerischer Wert: Excel-Prozentwert (0.5 = 50 %) oder Ganzzahl (50 = 50 %) + if isinstance(value, (int, float)): + if 0 < value <= 1: + return str(int(value * 100)) + if value == 0: + return "0" + # Wert > 1: bereits als Ganzzahl gemeint (z. B. 50) + return str(int(value)) + return str(value).strip() + + def _build_column_map(schema: list[FieldSchema]) -> dict[str, int]: """Baut ein Mapping von field_name → 0-basierter Spaltenindex.""" col_map: dict[str, int] = {} @@ -78,7 +91,8 @@ def parse_input_file( qualifikation = _to_text(row[col_map.get("Qualifikation", 0)]) if len(row) > col_map.get("Qualifikation", 0) else "" funktion = _to_text(row[col_map.get("Funktion", 0)]) if len(row) > col_map.get("Funktion", 0) else "" - stellenanteil = _to_float(row[col_map.get("Stellenanteil in %", 0)], "Stellenanteil in %") if len(row) > col_map.get("Stellenanteil in %", 0) else 0.0 + stellenanteil_raw = row[col_map.get("Stellenanteil in %", 0)] if len(row) > col_map.get("Stellenanteil in %", 0) else None + stellenanteil = _to_percent_string(stellenanteil_raw) monat = _to_text(row[col_map.get("Monat (MM.JJ)", 0)]) if len(row) > col_map.get("Monat (MM.JJ)", 0) else "" taetigkeit = _to_text(row[col_map.get("Tätigkeit", 0)]) if len(row) > col_map.get("Tätigkeit", 0) else "" record_id = _to_int_or_none(row[col_map.get("ID", 0)]) if len(row) > col_map.get("ID", 0) else None diff --git a/src/writer.py b/src/writer.py index ecc40bc..cde759e 100644 --- a/src/writer.py +++ b/src/writer.py @@ -5,7 +5,7 @@ Es werden KEINE Sheets programmatisch erzeugt oder kopiert – ausschließlich die vorhandenen Sheets mit Daten befüllt. """ -from datetime import date +import calendar from pathlib import Path from openpyxl import load_workbook @@ -95,18 +95,22 @@ def _fill_sheet(ws, record: EmployeeRecord, employee_name: str, field_map: dict) value = record.funktion elif source_field == "Tätigkeit": value = record.taetigkeit - elif source_field == "Ort": + elif source_field in ("Ort", "Ort 2"): value = "Dresden" elif source_field == "Datum": - value = date.today().strftime("%d.%m.%Y") + parts = record.monat.split(".") + if len(parts) == 2: + month = int(parts[0]) + year = int(parts[1]) + last_day = calendar.monthrange(year, month)[1] + value = f"{last_day:02d}.{month:02d}.{year}" + else: + value = "" else: continue formatted = _format_value(value, m.format) _set_cell_value(ws, m.target_cell, formatted) - # Datum zusätzlich ins Unterschriftsfeld - _set_cell_value(ws, "J95", date.today().strftime("%d.%m.%Y")) - def generate_activity_reports( employee_records: dict[str, list[EmployeeRecord]],