""" Stahování seznamu registrovaných pojištěnců VZP (111) — VZP Point (Playwright). VZP běží na ODLIŠNÉ platformě (point.vzp.cz) — ne portalzp.cz, ne eforms: - login: certifikát přes Chrome (auto-výběr z Windows store, politika AutoSelectCertificateForUrls), Playwright. Bez NMSigneru. - seznam: požaduje se podáním "Seznam registrovaných pojištěnců" s formátem výstupu "Datové rozhraní". Výsledek = datová dávka III-1.1.2 (soubor F111MMRR.nnn, CP852, hlavička H09305001), stažitelná z detailu zpracovaného podání. Tento skript STAHUJE výsledky už zpracovaných podání "Seznam registrovaných pojištěnců" (datová dávka) do složky SeznamyPojištěnců. Podání žádosti (NOVÉ PODÁNÍ) zatím dělá uživatel ručně na portálu — viz NOTES.md. Soubory dávek pak zpracovává Insurance/SeznamPojistencu/01_parse_seznam_dg_tool.py. """ import json import os import re import sys import time import winreg from pathlib import Path try: sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") except Exception: pass sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))) from Knihovny.najdi_dropbox import get_dropbox_root POINT_URL = "https://point.vzp.cz" DASHBOARD_URL = f"{POINT_URL}/Desk/FormDashboard" INBOX_URL = f"{POINT_URL}/Inbox/Message" # Sdílené s VZP skriptem pro stahování zpráv STAHUJ_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "StahováníZpráv", "111 VZP")) CHROME_PROFILE = os.path.join(STAHUJ_DIR, "chrome_profile") COOKIES_FILE = os.path.join(STAHUJ_DIR, "vzp_cookies.json") DEST_DIR = os.path.join( get_dropbox_root(), "Ordinace", "Dokumentace_ke_zpracování", "Zúčtovací zprávy", "SeznamyPojištěnců", ) CERT_ISSUER_CN = "I.CA Public CA/RSA 06/2022" # Název podání i přílohy PODANI_NAZEV = "Seznam registrovaných pojištěnců" DAVKA_RE = re.compile(r"^F\d{7}\.\d+$") # F111MMRR.nnn # Podání žádosti (REST API, ověřeno odchytem) PARTNER_ID = "3197807" # subjekt MUDr. Buzalková (partnerId z formuláře Form65) OUTPUT_FORMAT = "Text" # "Text" = Datové rozhraní (NE "Pdf"!) # Období podávané žádosti se zjistí automaticky z configu (nejnovější dostupné, viz # config.defaultModel / periodLimits.until). Pro ruční přepsání nastav OVERRIDE_OBDOBI # na (měsíc, rok), jinak ponech None. OVERRIDE_OBDOBI: tuple[int, int] | None = None # Kolikrát max. kliknout 'Načíst další' při hledání podání (dashboard míchá typy). # Stahování se stejně zastaví na první už stažené dávce, takže do minulosti nejde hluboko. MAX_LOADS = 8 def _set_chrome_cert_policy() -> None: policy = json.dumps({"pattern": "https://[*.]vzp.cz", "filter": {"ISSUER": {"CN": CERT_ISSUER_CN}}}) try: key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"SOFTWARE\Policies\Google\Chrome\AutoSelectCertificateForUrls") winreg.SetValueEx(key, "1", 0, winreg.REG_SZ, policy) winreg.CloseKey(key) except Exception as e: print(f" Varování: nelze nastavit Chrome politiku: {e}") def _load_cookies(context) -> int: if not os.path.exists(COOKIES_FILE): return 0 try: with open(COOKIES_FILE, encoding="utf-8") as f: context.add_cookies(json.load(f)) return 1 except Exception: return 0 def _save_cookies(context) -> None: try: vzp = [c for c in context.cookies() if "vzp.cz" in c.get("domain", "")] with open(COOKIES_FILE, "w", encoding="utf-8") as f: json.dump(vzp, f, indent=2, ensure_ascii=False) except Exception: pass def prihlaseni(context): """Zajistí přihlášení na VZP Point. Vrátí přihlášenou page.""" _load_cookies(context) page = context.new_page() page.goto(DASHBOARD_URL, wait_until="domcontentloaded", timeout=30_000) if page.url.startswith("https://auth.vzp.cz/signin"): print("Přihlašuji certifikátem...") cert_btn = page.locator("a, button").filter(has_text=re.compile(r"certifikát", re.I)).first cert_btn.wait_for(state="visible", timeout=10_000) cert_btn.click(no_wait_after=True) try: page.wait_for_url("https://point.vzp.cz/**", timeout=60_000) except Exception: pass if not page.url.startswith(POINT_URL): raise RuntimeError(f"Přihlášení selhalo. URL: {page.url}") print("Přihlášení OK.") _save_cookies(context) return page def _bearer_token(page) -> str: """Vytáhne Bearer token z inline