diff --git a/backend-compliance/compliance/services/founding_wizard/markdown_to_docx.py b/backend-compliance/compliance/services/founding_wizard/markdown_to_docx.py index 0131cd85..b92aec6e 100644 --- a/backend-compliance/compliance/services/founding_wizard/markdown_to_docx.py +++ b/backend-compliance/compliance/services/founding_wizard/markdown_to_docx.py @@ -30,7 +30,12 @@ TABLE_ROW_RE = re.compile(r"^\|(.+)\|\s*$") TABLE_SEP_RE = re.compile(r"^\|[\s\-:|]+\|\s*$") INLINE_BOLD = re.compile(r"\*\*([^*]+)\*\*") -INLINE_ITALIC = re.compile(r"(? str: return "\n".join(bullets) if bullets else "a) Allgemeine geschäftliche Tätigkeit" +def _roles_description(gesellschafter: list[dict[str, Any]]) -> str: + """Generiert Anlage-A Rollenbeschreibung pro Gesellschafter.""" + lines = [] + for idx, g in enumerate(gesellschafter): + name = g.get("name", "") + role = g.get("internal_role") or "Gesellschafter" + lines.append(f"({idx + 2}) **{role} — {name}**") + lines.append(f"Verantwortlich für die operative Leitung im Bereich {role}.\n") + return "\n".join(lines) + + def _einzahlungsaufstellung(gesellschafter: list[dict[str, Any]], quote_pct: int) -> str: rows = [] for g in gesellschafter: @@ -174,5 +185,100 @@ def base_context(state: dict[str, Any]) -> dict[str, Any]: "HAS_HRB": False, "HRB_NUMBER": "[wird vergeben]", "IS_UG": basics.get("legal_form") == "UG", + # GO-GF dynamische §-Numerierung + "P_INFO": 5, + "P_GESELLSCHAFTER": 4 if num_gf == 1 else 4, + "P_AUSSER": 5, + "P_ENT": 6, + "P_FIN": 7, + "P_PERS": 8, + "P_IK": 9, + "P_NEB": 10, + "P_DOC": 10, + "P_DOC_NEXT": 2, + "P_DOC_NEXT_2": 3, + "P_END": 11, + "LAST_PARA_4": 4 if num_gf == 2 else 5, + # SHA dynamische §-Numerierung (mit/ohne Beirat) + "P_NONCOMPETE": 16 if sha.get("has_beirat") else 15, + "P_CONFIDENTIAL": 17 if sha.get("has_beirat") else 16, + "P_TERM": 18 if sha.get("has_beirat") else 17, + "P_FINAL": 19 if sha.get("has_beirat") else 18, + "P_IP_PARA_6": 6 if has_academic else 3, + "P_IP_PARA_7": 7 if has_academic else 4, + "P_IP_PARA_8": 8 if has_academic else 5, + "P_DEADLOCK_FINAL": 5, + "P_DEADLOCK_LAST": 6, + "LAST_ROLE_PARA": len(gesellschafter) + 2, + "LAST_ROLE_PARA_PLUS_1": len(gesellschafter) + 3, + # Satzung dynamische §-Numerierung + "P_EINZIEHUNG": 7, + "P_VORKAUF": 8, + "P_TAGALONG": 9, + "P_DRAGALONG": 10, + "P_VERSAMMLUNG": 11, + "P_JA": 12, + "P_ERGEBNIS": 13, + "P_AUFGRIFF": 14, + "P_ABTRETUNG": 15, + "P_ERBE": 16, + "P_AUFL": 17, + "P_SCHLUSS": 18, + # SHA Eskalation und sonstige Schwellenwerte + "ESKALATION_TAGE_INTERN": 5, + "ESKALATION_TAGE_GESELLSCHAFTER": 14, + "ERHEBLICH_EUR": "10.000", + "DEADLOCK_FRIST_TAGE": 30, + "MEDIATION_INIT_TAGE": 7, + "MEDIATOR_FRIST_TAGE": 5, + "MEDIATION_MAX_TAGE": 30, + "SHOOTOUT_FRIST_TAGE": 14, + "SHOOTOUT_ABWICKLUNG_TAGE": 60, + "ESKALATION_TAGE": 30, + "JURISDICTION_LOCATION": basics.get("company_seat", "[Sitz]"), + "PARA_181_DETAILS": "soweit Geschäftsführer von den Beschränkungen befreit", + "ARCHIV_VERANTWORTLICH": "Geschäftsführung", + "DOKUMENTATIONS_SYSTEM": "elektronischen Dokumentenmanagement", + "ARCHIVIERUNG_JAHRE": 10, + "REVIEW_VERANTWORTLICH": "Geschäftsführung", + "MEETING_OPERATIVE_FREQ": "wöchentliche", + "MEETING_STRATEGIE_FREQ": "monatliche", + "SCHWELLE_EINZEL_EUR": "10.000", + "SCHWELLE_EINZEL_EUR_PLUS_1": "10.001", + "SCHWELLE_GEMEINSAM_EUR": "50.000", + "SCHWELLE_GESELLSCHAFTER_EUR": "50.000", + "BUDGET_ABWEICHUNG_PCT": 10, + "VERTRAG_LAUFZEIT_MONATE": 24, + "VERTRAG_WERT_EUR": "50.000", + "LIQUIDITAET_MIN_MONATE": 3, + "FORECAST_HORIZON_MONTHS": 12, + "SCHLUESSELPERSON_GEHALT_EUR": "80.000", + "NEBENTAETIGKEIT_MAX_STUNDEN": 8, + # SHA-Spezifika + "VESTING_START_EVENT": "Eintragung der Gesellschaft im Handelsregister", + "VESTING_MONTHS": sha.get("vesting_months", 48), + "CLIFF_MONTHS": sha.get("cliff_months", 12), + "ACCELERATION_THRESHOLD_PCT": 50, + "ACCELERATION_PCT": 100, + "BAD_LEAVER_UNVESTED_PCT": 20, + "FMV_AGREEMENT_DAYS": 14, + "ABFINDUNG_RATEN_MAX": 24, + "NON_SOLICIT_MONTHS": 12, + "VORKAUFSRECHT_TAGE": 14, + "TAG_ALONG_THRESHOLD_PCT": sha.get("tag_along_threshold_pct", 20), + "TAG_ALONG_FRIST_TAGE": 14, + "DRAG_ALONG_THRESHOLD_PCT": sha.get("drag_along_threshold_pct", 75), + "RESERVED_MATTERS_MAJORITY_PCT": sha.get("reserved_matters_majority_pct", 75), + "ASSET_THRESHOLD_EUR": "50.000", + "ESOP_POOL_PCT": sha.get("esop_pool_pct", 0), + "INVESTOR_INFO_THRESHOLD_EUR": "50.000", + "ANNUAL_REPORT_MONTHS": 6, + "BEIRAT_MAX_MITGLIEDER": 5, + "BEIRAT_FREQ": "vierteljährlich", + "PASSIVE_INVEST_PCT": 5, + "POST_EXIT_GOOD_MONTHS": 12, + "POST_EXIT_BAD_MONTHS": 24, + "ROLES_DESCRIPTION": _roles_description(gesellschafter), + "SIGNATURE_DATE": notar.get("notarial_date", "[Datum]"), } return ctx