fix: Stellenanteil in Prozentangabe und jeweiliges Monatsende als Datum eintragen

This commit is contained in:
trnq1ll0 committed 2026-06-10 17:03:46 +02:00
1 parent 0d390f79b4
commit b05849e673
4 files changed
+38 -19

No files matched your search

+2 -1
View File
@@ -1,11 +1,12 @@
[ [
{"source_field": "Antragsnummer", "target_cell": "B3", "format": null}, {"source_field": "Antragsnummer", "target_cell": "B3", "format": null},
{"source_field": "Name", "target_cell": "B17", "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": "Qualifikation", "target_cell": "B21", "format": null},
{"source_field": "Monat (MM.JJ)", "target_cell": "R21", "format": null}, {"source_field": "Monat (MM.JJ)", "target_cell": "R21", "format": null},
{"source_field": "Funktion", "target_cell": "B25", "format": null}, {"source_field": "Funktion", "target_cell": "B25", "format": null},
{"source_field": "Tätigkeit", "target_cell": "B31", "format": null}, {"source_field": "Tätigkeit", "target_cell": "B31", "format": null},
{"source_field": "Ort", "target_cell": "B95", "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} {"source_field": "Datum", "target_cell": "J95", "format": null}
] ]
+1 -1
View File
@@ -11,7 +11,7 @@ class EmployeeRecord:
antragsnummer: str antragsnummer: str
qualifikation: str qualifikation: str
funktion: str funktion: str
stellenanteil: float stellenanteil: str
monat: str # z. B. "01.2025" monat: str # z. B. "01.2025"
taetigkeit: str taetigkeit: str
id: Optional[int] = None id: Optional[int] = None
+25 -11
View File
@@ -17,16 +17,6 @@ def _to_text(value: Any) -> str:
return str(value).strip() 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]: def _to_int_or_none(value: Any) -> Optional[int]:
if value is None or str(value).strip() == "": if value is None or str(value).strip() == "":
return None return None
@@ -36,6 +26,29 @@ def _to_int_or_none(value: Any) -> Optional[int]:
return None 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]: def _build_column_map(schema: list[FieldSchema]) -> dict[str, int]:
"""Baut ein Mapping von field_name → 0-basierter Spaltenindex.""" """Baut ein Mapping von field_name → 0-basierter Spaltenindex."""
col_map: dict[str, int] = {} 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 "" 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 "" 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 "" 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 "" 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 record_id = _to_int_or_none(row[col_map.get("ID", 0)]) if len(row) > col_map.get("ID", 0) else None
+10 -6
View File
@@ -5,7 +5,7 @@ Es werden KEINE Sheets programmatisch erzeugt oder kopiert –
ausschließlich die vorhandenen Sheets mit Daten befüllt. ausschließlich die vorhandenen Sheets mit Daten befüllt.
""" """
from datetime import date import calendar
from pathlib import Path from pathlib import Path
from openpyxl import load_workbook from openpyxl import load_workbook
@@ -95,18 +95,22 @@ def _fill_sheet(ws, record: EmployeeRecord, employee_name: str, field_map: dict)
value = record.funktion value = record.funktion
elif source_field == "Tätigkeit": elif source_field == "Tätigkeit":
value = record.taetigkeit value = record.taetigkeit
elif source_field == "Ort": elif source_field in ("Ort", "Ort 2"):
value = "Dresden" value = "Dresden"
elif source_field == "Datum": 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: else:
continue continue
formatted = _format_value(value, m.format) formatted = _format_value(value, m.format)
_set_cell_value(ws, m.target_cell, formatted) _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( def generate_activity_reports(
employee_records: dict[str, list[EmployeeRecord]], employee_records: dict[str, list[EmployeeRecord]],