From 64d022d016ed541c8f82a341111247d8f9940371 Mon Sep 17 00:00:00 2001 From: mia Date: Wed, 17 Jun 2026 09:04:35 +0200 Subject: [PATCH] schizo v4 working export --- .gitignore | 3 + Entschuldigung16062026.pdf | Bin 52535 -> 0 bytes main.py | 332 +++++++++++++++++++++---------------- 3 files changed, 193 insertions(+), 142 deletions(-) create mode 100644 .gitignore delete mode 100644 Entschuldigung16062026.pdf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e48794e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pdf + +!Entschuldigung_template.pdf diff --git a/Entschuldigung16062026.pdf b/Entschuldigung16062026.pdf deleted file mode 100644 index 6df1b8274e9f52f885f23fd51daaecda7646408d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52535 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 str: # ─── PDF filling ─────────────────────────────────────────────────────────────── -def fill_entschuldigung( - template_path: str, - output_dir: str, - student_name: str, - student_class: str, - absence_dates: str, # e.g. "12.06.2025 – 13.06.2025" - reason: str, - total_hours: int, - workshop_hours: int, - sign_date: str, # e.g. "16.06.2025" -) -> str: - """Fill the Entschuldigung PDF form and return the output path.""" - try: - from pypdf import PdfReader, PdfWriter - except ImportError: - raise RuntimeError("pypdf is required: pip install pypdf") - - reader = PdfReader(template_path) - writer = PdfWriter() - writer.append(reader) - - # Field mapping (confirmed from extract_form_field_info): - # Textfeld 1 → Name des Schülers - # Textfeld 2 → Klasse - # Textfeld 4 → Versäumte(r) Unterrichtstag(e) / Datum - # Textfeld 3 → Begründung für das Fernbleiben - # Textfeld 5 → Zahl der versäumten Unterrichtsstunden - # Textfeld 6 → davon versäumte Werkstättenstunden - # Textfeld 7 → Datum (signature date, bottom left) - - fields = { - "Textfeld 1": student_name, - "Textfeld 2": student_class, - "Textfeld 4": absence_dates, - "Textfeld 3": reason, - "Textfeld 5": str(total_hours), - "Textfeld 6": str(workshop_hours), - "Textfeld 7": sign_date, - } - - writer.update_page_form_field_values(writer.pages[0], fields) - - # Derive date for filename from absence_dates (take first date portion) - try: - first_date = absence_dates.split("–")[0].strip().split(" ")[0] - dt = datetime.strptime(first_date, "%d.%m.%Y") - date_suffix = dt.strftime("%d%m%Y") - except Exception: - date_suffix = datetime.now().strftime("%d%m%Y") - - output_filename = f"Entschuldigung{date_suffix}.pdf" - output_path = os.path.join(output_dir, output_filename) - - with open(output_path, "wb") as f: - writer.write(f) - - return output_path - # ─── PDF export dialog ───────────────────────────────────────────────────────── +def _absence_date_str(ab: dict) -> str: + """Return the absence date as DD.MM.YYYY string.""" + dv = ab.get("date") or ab.get("startDate", "") + try: + d = str(dv) + return f"{d[6:8]}.{d[4:6]}.{d[:4]}" + except Exception: + return str(dv) + + +def _absence_date_suffix(ab: dict) -> str: + """Return DDMMYYYY for use in the filename.""" + dv = ab.get("date") or ab.get("startDate", "") + try: + d = str(dv) + return f"{d[6:8]}{d[4:6]}{d[:4]}" + except Exception: + return datetime.now().strftime("%d%m%Y") + + def run_pdf_export_dialog( absences: list[dict], template_path: str, student_name: str, student_class: str, + cfg: dict | None = None, ) -> None: - """Simple terminal prompts to collect data and fill the PDF.""" + """ + For each selected absence, generate one individual PDF named + EntschuldigungDDMMYYYY.pdf where the date is the absence date. + """ print("\n─── Export Entschuldigung PDF ─────────────────────────────") - # Pick absence(s) to excuse - unexcused = [a for a in absences if _is_unexcused(a)] + # Show unexcused absences grouped by date (newest first) + unexcused = filter_absences(absences, unexcused_only=True) if not unexcused: print("No unexcused absences found.") return - print("\nUnexcused absences:") - for i, ab in enumerate(unexcused[:20]): - date_val = ab.get("date") or ab.get("startDate", "") - start = ab.get("startTime") or ab.get("lessonStartTime", "") - print(f" [{i+1}] {_parse_dt(date_val, start)}") + # Group by date so the user can see days clearly + from collections import defaultdict + by_date: dict[str, list[dict]] = defaultdict(list) + for ab in unexcused: + by_date[_absence_date_str(ab)].append(ab) - sel = input("\nEnter number(s) to excuse (comma-separated, or 'all'): ").strip() + dates_in_order = list(dict.fromkeys(_absence_date_str(ab) for ab in unexcused)) + + print("\nUnexcused absences (one PDF will be created per entry):") + idx = 0 + entry_map: list[dict] = [] # flat list matching printed numbers + for ds in dates_in_order: + print(f" {ds}") + for ab in by_date[ds]: + start = ab.get("startTime") or ab.get("lessonStartTime", "") + end = ab.get("endTime") or ab.get("lessonEndTime", "") + subject = ab.get("subject") or ab.get("subjectLong") or "—" + minutes = ab.get("absentTime") or ab.get("minutesAbsent") or "?" + t_start = str(start).zfill(4) + t_end = str(end).zfill(4) if end else "" + time_str = f"{t_start[:2]}:{t_start[2:]}" + if t_end: + time_str += f"–{t_end[:2]}:{t_end[2:]}" + print(f" [{idx+1}] {time_str} {subject} ({minutes} min)") + entry_map.append(ab) + idx += 1 + + sel = input("\nEnter number(s) to export (comma-separated, or 'all'): ").strip() if sel.lower() == "all": - selected = unexcused[:20] + selected = entry_map else: - indices = [int(x.strip()) - 1 for x in sel.split(",") if x.strip().isdigit()] - selected = [unexcused[i] for i in indices if 0 <= i < len(unexcused)] + indices = [int(x.strip()) - 1 for x in sel.split(",") if x.strip().isdigit()] + selected = [entry_map[i] for i in indices if 0 <= i < len(entry_map)] if not selected: print("No valid selection.") return - # Build date string - dates_sorted = sorted(selected, key=_absence_sort_key) - date_strs = [] - for ab in dates_sorted: - dv = ab.get("date") or ab.get("startDate", "") + # ── Shared fields (same for every PDF) ────────────────────────────── + cfg = cfg or {} + saved_name = student_name or cfg.get("student_name", "") + saved_class = student_class or cfg.get("student_class", "") + + print() + + # Yolo mode — accept all defaults, only stop for truly unknown values + yolo = input(" Yolo mode — accept all defaults? [y/N]: ").strip().lower() == "y" + print() + + # Name — always prompt if unknown (even in yolo) + if not saved_name: + saved_name = input(" Student name (required): ").strip() + elif not yolo: + v = input(f" Student name [{saved_name}]: ").strip() + if v: + saved_name = v + final_name = saved_name + + # Class — always prompt if unknown + if not saved_class: + saved_class = input(" Class (required): ").strip() + elif not yolo: + v = input(f" Class [{saved_class}]: ").strip() + if v: + saved_class = v + final_class = saved_class + + save_config({"student_name": final_name, "student_class": final_class}) + + sign_date_default = datetime.now().strftime("%d.%m.%Y") + saved_output_dir = cfg.get("output_dir", os.getcwd()) + + if yolo: + sign_date = sign_date_default + output_dir = saved_output_dir + else: + v = input(f" Signature date [{sign_date_default}]: ").strip() + sign_date = v if v else sign_date_default + v = input(f" Save to directory [{saved_output_dir}]: ").strip() + output_dir = v if v else saved_output_dir + save_config({"output_dir": output_dir}) + + # ── Per-entry prompts + PDF generation ────────────────────────────── + from pypdf import PdfReader, PdfWriter + + print() + saved_files, failed = [], [] + for ab in selected: + absence_date = _absence_date_str(ab) + start_raw = ab.get("startTime") or ab.get("lessonStartTime", "") + t = str(start_raw).zfill(4) + label = f"{absence_date} {t[:2]}:{t[2:]}" # e.g. "16.06.2026 11:40" + + minutes_raw = ab.get("absentTime") or ab.get("minutesAbsent") or 50 + default_hours = max(1, round(int(minutes_raw) / 50)) + default_reason = ab.get("reason") or ab.get("text") or "Krankheit" + default_workshop = 0 + + if yolo: + final_reason = default_reason + final_hours = default_hours + final_workshop = default_workshop + else: + r = input(f" Reason {label} [{default_reason}]: ").strip() + final_reason = r if r else default_reason + + h = input(f" Hours {label} [{default_hours}]: ").strip() + final_hours = int(h) if h.isdigit() else default_hours + + w = input(f" Workshop {label} [{default_workshop}]: ").strip() + final_workshop = int(w) if w.isdigit() else default_workshop + + filename = f"Entschuldigung{_absence_date_suffix(ab)}.pdf" + out_path = os.path.join(output_dir, filename) try: - d = str(dv) - date_strs.append(f"{d[6:8]}.{d[4:6]}.{d[:4]}") - except Exception: - date_strs.append(str(dv)) - unique_dates = list(dict.fromkeys(date_strs)) - absence_dates = ", ".join(unique_dates) + reader = PdfReader(template_path) + writer = PdfWriter() + writer.append(reader) + writer.update_page_form_field_values(writer.pages[0], { + "Textfeld 1": final_name, + "Textfeld 2": final_class, + "Textfeld 4": absence_date, + "Textfeld 3": final_reason, + "Textfeld 5": str(final_hours), + "Textfeld 6": str(final_workshop), + "Textfeld 7": sign_date, + }) + with open(out_path, "wb") as f: + writer.write(f) + print(f" ✅ {filename}") + saved_files.append(out_path) + except Exception as e: + print(f" ❌ {filename}: {e}") + failed.append(filename) - # Count hours (each absence period ≈ 1 lesson; use absentTime if available) - total_minutes = sum( - int(ab.get("absentTime") or ab.get("minutesAbsent") or 50) - for ab in selected - ) - total_hours = max(1, round(total_minutes / 50)) - - # Prompt user for details - print(f"\n Student name : {student_name or '(unknown)'}") - name_input = input(f" Override name? [Enter to keep]: ").strip() - final_name = name_input if name_input else student_name - - print(f" Class : {student_class or '(unknown)'}") - class_input = input(f" Override class? [Enter to keep]: ").strip() - final_class = class_input if class_input else student_class - - print(f" Absence date(s): {absence_dates}") - date_override = input(f" Override date(s)? [Enter to keep]: ").strip() - final_dates = date_override if date_override else absence_dates - - default_reason = (selected[0].get("reason") or selected[0].get("text") or "Krankheit") - reason_input = input(f" Reason [{default_reason}]: ").strip() - final_reason = reason_input if reason_input else default_reason - - print(f" Total lessons missed: {total_hours}") - hours_input = input(f" Override? [Enter to keep]: ").strip() - final_hours = int(hours_input) if hours_input.isdigit() else total_hours - - workshop_input = input(f" Workshop hours missed [0]: ").strip() - final_workshop = int(workshop_input) if workshop_input.isdigit() else 0 - - sign_date = input( - f" Signature date [{datetime.now().strftime('%d.%m.%Y')}]: " - ).strip() or datetime.now().strftime("%d.%m.%Y") - - output_dir = input( - f" Save to directory [{os.getcwd()}]: " - ).strip() or os.getcwd() - - try: - out = fill_entschuldigung( - template_path=template_path, - output_dir=output_dir, - student_name=final_name, - student_class=final_class, - absence_dates=final_dates, - reason=final_reason, - total_hours=final_hours, - workshop_hours=final_workshop, - sign_date=sign_date, - ) - print(f"\n✅ Saved: {out}\n") - except Exception as e: - print(f"\n❌ Failed to fill PDF: {e}\n") + print(f"\n Done: {len(saved_files)} saved, {len(failed)} failed.\n") # ─── TUI ────────────────────────────────────────────────────────────────────── @@ -441,6 +459,7 @@ def run_tui( template_path: str | None, student_name: str, student_class: str, + cfg: dict | None = None, ) -> None: state = { "filter": False, # True = show only unexcused @@ -523,18 +542,41 @@ def run_tui( template_path=template_path, student_name=student_name, student_class=student_class, + cfg=cfg or {}, ) +# ─── Config file ────────────────────────────────────────────────────────────── + +CONFIG_PATH = Path.home() / ".webuntis_absence_viewer.json" + +def load_config() -> dict: + try: + return json.loads(CONFIG_PATH.read_text()) + except Exception: + return {} + +def save_config(data: dict) -> None: + try: + existing = load_config() + existing.update(data) + CONFIG_PATH.write_text(json.dumps(existing, indent=2)) + except Exception: + pass + + # ─── CLI ────────────────────────────────────────────────────────────────────── -def prompt_missing(args): +def prompt_missing(args, cfg: dict) -> None: if not args.server: - args.server = input("WebUntis server (e.g. mese.webuntis.com): ").strip() + default = cfg.get("server", "") + args.server = input(f"WebUntis server [{default}]: ").strip() or default if not args.school: - args.school = input("School name (from the WebUntis URL): ").strip() + default = cfg.get("school", "") + args.school = input(f"School name [{default}]: ").strip() or default if not args.username: - args.username = input("Username: ").strip() + default = cfg.get("username", "") + args.username = input(f"Username [{default}]: ").strip() or default if not args.password: args.password = getpass.getpass("Password: ") @@ -551,7 +593,11 @@ def main(): default=None) args = parser.parse_args() - prompt_missing(args) + cfg = load_config() + prompt_missing(args, cfg) + + # Persist server/school/username for next run + save_config({"server": args.server, "school": args.school, "username": args.username}) end_date = date.today() start_date = end_date - timedelta(days=args.days) @@ -563,8 +609,9 @@ def main(): print("Logging in …") client.login(args.username, args.password) - student_name = client.display_name - student_class = client.get_student_class() + # Use API result; fall back to saved values from config + student_name = client.display_name or cfg.get("student_name", "") + student_class = client.get_student_class() or cfg.get("student_class", "") print(f"Logged in as: {args.username}" + (f" (name: {student_name})" if student_name else "")) @@ -586,6 +633,7 @@ def main(): template_path=args.template, student_name=student_name, student_class=student_class, + cfg=cfg, )