#!/usr/bin/env python3 """Apply 'Büromiete ab Sep 2027 → 1000€/Monat' to Finanzplan-Wandeldarlehen-400k Base/Bull/Bear scenarios. Updates row 27 (raumkosten) in 'Betriebliche Aufwendungen' sheet of each file. Existing label is renamed to 'Büromiete (ab Sep 2027)'. Usage: python3 pitch-deck/scripts/apply-bueromiete.py python3 pitch-deck/scripts/apply-bueromiete.py --dry-run """ from __future__ import annotations import argparse import shutil import sys from datetime import datetime from pathlib import Path from openpyxl import load_workbook from openpyxl.utils import get_column_letter EXPORTS = Path(__file__).resolve().parent.parent / "exports" TARGETS = [ "Finanzplan-Wandeldarlehen-400k.xlsx", "Finanzplan-Wandeldarlehen-400k-Bull.xlsx", "Finanzplan-Wandeldarlehen-400k-Bear.xlsx", ] RENT_ROW = 27 RENT_AMOUNT = 1000 START_YEAR = 2027 START_MONTH = 9 NEW_LABEL = "Büromiete (ab Sep 2027)" def find_start_col(ws) -> int: for c in range(2, ws.max_column + 1): if ws.cell(row=1, column=c).value == START_YEAR and ws.cell(row=2, column=c).value == START_MONTH: return c raise RuntimeError(f"Could not find {START_MONTH}/{START_YEAR} in header rows") def process_file(path: Path, dry_run: bool) -> tuple[int, int, int]: wb = load_workbook(path) if "Betriebliche Aufwendungen" not in wb.sheetnames: raise RuntimeError(f"{path.name}: missing 'Betriebliche Aufwendungen' sheet") ws = wb["Betriebliche Aufwendungen"] current_label = ws.cell(row=RENT_ROW, column=1).value if current_label is None or "raumkosten" not in str(current_label).lower() and "raum" not in str(current_label).lower() and "miete" not in str(current_label).lower() and "büro" not in str(current_label).lower(): raise RuntimeError(f"{path.name}: row {RENT_ROW} label is {current_label!r}, expected raumkosten/raum/miete/büro") ws.cell(row=RENT_ROW, column=1).value = NEW_LABEL start_col = find_start_col(ws) end_col = ws.max_column for c in range(start_col, end_col + 1): ws.cell(row=RENT_ROW, column=c).value = RENT_AMOUNT if not dry_run: wb.save(path) return start_col, end_col, end_col - start_col + 1 def backup(path: Path) -> Path: ts = datetime.now().strftime("%Y%m%d-%H%M%S") bk = path.with_name(f"{path.stem}.BACKUP-pre-bueromiete-{ts}{path.suffix}") shutil.copy2(path, bk) return bk def main() -> int: ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("--dry-run", action="store_true") ap.add_argument("--no-backup", action="store_true") args = ap.parse_args() for name in TARGETS: path = EXPORTS / name if not path.exists(): print(f" ⚠ skip (not found): {name}", file=sys.stderr) continue if not args.dry_run and not args.no_backup: bk = backup(path) print(f" ✓ backup: {bk.name}") start_col, end_col, n = process_file(path, dry_run=args.dry_run) print( f" {name}: row {RENT_ROW} → '{NEW_LABEL}', " f"cols {get_column_letter(start_col)}..{get_column_letter(end_col)} = {RENT_AMOUNT}€ ({n} months)" ) return 0 if __name__ == "__main__": sys.exit(main())