diff --git a/Insurance/KdoJeLékař/NOTES.md b/Insurance/KdoJeLékař/NOTES.md
index 8bef44c..2310c90 100644
--- a/Insurance/KdoJeLékař/NOTES.md
+++ b/Insurance/KdoJeLékař/NOTES.md
@@ -6,6 +6,30 @@ Zjistit pro pacienty z Medicus DB, kdo je jejich registrující **praktický lé
---
+## Stav k 29. 4. 2026 — hotovo
+
+- Certifikát ✅, tabulky ✅, produkční skript ✅
+- Připraveno ke spuštění — přepnout `TEST_MODE = False`
+
+---
+
+## Soubory v tomto adresáři
+
+| Soubor | Popis |
+|--------|-------|
+| `kdojelekar_tydenni.py` | Produkční skript — batch všech pacientů, ukládá do MySQL |
+| `_test_temp.py` | Testovací skript — dotaz na jedno RC, výpis XML + parsovaný výsledek |
+| `_test_no_odb.py` | Test bez filtru odborností — sloužil k ověření struktury odpovědi |
+
+---
+
+## Certifikát
+
+**`u:\ordinaceprojekt\Insurance\Certificates\picka.pfx`** / heslo **`Vlado7309208104+`**
+Ověřeno 29. 4. 2026 (HTTP 200). Stejný certifikát používá i `StavPojisteni\zkontroluj_a_odesli_zlomy.py`.
+
+---
+
## VZP B2B služba: `RegistracePojistencePZSB2B`
### Endpoint (produkce)
@@ -14,89 +38,71 @@ https://prod.b2b.vzp.cz/B2BProxy/HttpProxy/RegistracePojistencePZSB2B
```
### Autentizace
-mTLS — klientský certifikát `.pfx` od **I.CA** (První certifikační autorita).
-Stejný mechanismus jako u `stavPojisteniB2B`.
-
-### SOAP požadavek
-```xml
-
- 7309208104
- 2026-04-28
-
- 001
- 002
- 014
-
-
-```
-
-XML namespace odpovědi: `http://xmlns.gemsystem.cz/B2B/RegistracePojistencePZSB2B/1`
+mTLS — klientský certifikát `.pfx`, stejný mechanismus jako u `stavPojisteniB2B`.
### Struktura odpovědi
-Pro každou odbornost vrátí jeden `` element:
+Pro každou odbornost kde má pacient lékaře vrátí jeden `` element.
+Pokud lékař není, VZP element vynechá — skript ukládá placeholder řádek s `ma_lekare=0`.
-| XML tag | Popis |
-|---------|-------|
-| `ICZ` | IČZ zdravotnického zařízení |
-| `ICP` | IČP lékaře |
-| `nazevICP` | Jméno lékaře |
-| `nazevSZZ` | Název zdravotnického zařízení |
-| `zdravotniPojistovna/kod` | Kód pojišťovny pacienta |
-| `zdravotniPojistovna/zkratka` | Zkratka pojišťovny |
-| `odbornost/kod` | Kód odbornosti (001/002/014) |
-| `odbornost/nazev` | Název odbornosti |
-| `datumRegistrace` | Datum registrace u tohoto lékaře |
-| `datumZahajeni` | Začátek registrace |
-| `datumUkonceni` | Konec registrace (null = stále aktivní) |
-| `stavVyrizeniPozadavku` | Stavový kód odpovědi VZP |
+| XML tag | Uloženo jako | Popis |
+|---------|-------------|-------|
+| `ICZ` | `ICZ` | IČZ zdravotnického zařízení |
+| `ICP` | `ICP` | IČP lékaře |
+| `nazevICP` | `nazev_lekare` | Název pracoviště |
+| `nazevSZZ` | `nazev_zzz` | Jméno lékaře |
+| `zdravotniPojistovna/kod` | `poj_kod` | Kód pojišťovny pacienta |
+| `zdravotniPojistovna/zkratka` | `poj_zkratka` | Zkratka pojišťovny |
+| `odbornost/kod` | `kod_odbornosti` | Kód odbornosti (001/002/014) |
+| `datumRegistrace` | `datum_registrace` | Kdy pacient podepsal registraci |
+| `datumZahajeni` | `datum_zahajeni` | Od kdy registrace platí u VZP |
+| `datumUkonceni` | `datum_ukonceni` | Do kdy (3000-01-01 = bez konce) |
+| `stavVyrizeniPozadavku` | `stav_vyrizeni` | Stavový kód odpovědi VZP |
-Pokud pacient nemá v dané odbornosti registrovaného lékaře, VZP vrátí prázdný seznam — je třeba uložit placeholder řádek (viz vzor v `u:\insurance\02.2 Testík.py`, funkce `upsert_rows`, negativní cesta).
+**Poznámka k parsování:** VZP vrací pro každý nalezený záznam dva `` elementy —
+vnější (s ICZ/ICP/jménem) a vnořený subelement (jen kód+název). Parser používá
+`findall(".//seznamOdbornosti/odbornost")` který zachytí jen vnější.
---
-## Zdrojový kód pro inspiraci
+## MySQL tabulky
-Vše je hotové v `u:\insurance\`, stačí přenést a adaptovat:
+### `vzp_registrace_lekari`
+Jeden řádek na `(rc, k_datu, kod_odbornosti)`. UNIQUE klíč = `(rc, k_datu, kod_odbornosti)`.
+Historie se hromadí — každý týdenní běh přidá nové řádky.
-| Soubor | Co obsahuje |
-|--------|-------------|
-| `u:\insurance\02 testík.py` | Hlavní logika: `build_envelope`, `parse_registrace`, `upsert_rows`, batch smyčka přes Medicus KAR |
-| `u:\insurance\02.2 Testík.py` | Vylepšená verze — ukládá i negativní výsledky (pacient bez lékaře) |
-| `u:\insurance\functions.py` | `get_medicus_connection()`, `get_mysql_connection()` — připojení k Firebird a MySQL |
-| `u:\insurance\knihovny\vzpb2b_client.py` | Třída `VZPB2BClient` — obecný mTLS klient pro VZP B2B |
+### `vzp_registrace_raw`
+Jeden řádek na `(rc, k_datu)` — celé raw XML odpovědi.
+Slouží k případnému přepočtu bez opakování API dotazů. UNIQUE klíč = `(rc, k_datu)`.
---
-## Certifikáty — stav k 28. 4. 2026
+## Produkční skript `kdojelekar_tydenni.py`
-| Soubor | Platnost | Stav |
-|--------|----------|------|
-| `u:\insurance\Certificates\MBcert.pfx` | do 22. 1. 2026 | **EXPIROVAL** |
-| `u:\insurance\10 Tests\MBcert.pfx` | do 22. 1. 2026 | **EXPIROVAL** |
-| `u:\insurance\Certificates\ICAPublicMBdo16JAN2027.pfx` | do cca. 16. 1. 2027 | Platný, ale **neznáme heslo** — zjistit! |
-| `u:\ordinaceprojekt\Insurance\Certificates\MBQualifiedCert.pfx` | do 16. 1. 2027 | Platný, ale **VZP odmítá** (kvalifikovaný certifikát, ne komerční) |
-| `u:\ordinaceprojekt\Insurance\Certificates\picka.pfx` | neznámá | Neznáme heslo |
-| `u:\insurance\Certificates\picka.pfx` | neznámá | Neznáme heslo |
+### Konfigurace (začátek souboru)
+| Proměnná | Výchozí | Popis |
+|----------|---------|-------|
+| `API_PAUSE` | `2` | Sekundy mezi VZP dotazy |
+| `TEST_MODE` | `True` | False = produkční běh |
+| `ODBORNOSTI` | `["001","002","014"]` | Dotazované odbornosti |
-### Klíčový problém k vyřešení jako první
-**`ICAPublicMBdo16JAN2027.pfx` je pravděpodobně správný certifikát** (název naznačuje I.CA, správná CA pro VZP B2B, platný do 2027). Vyzkoušená hesla nepasují:
-- `Vlado7309208104++`, `vlado7309208104++`, `7309208104`, `Vlado9674+`, `masterkey`, `""`
+### Logika
+1. Načte aktivně registrované pacienty z Medicus (přesný select dle SELECTS.md, IČP 09305001)
+2. V produkčním běhu přeskočí pacienty, kteří už mají záznam v `vzp_registrace_raw` pro dnešní datum — **resumovatelný běh**
+3. Pro každého pacienta zavolá VZP B2B, uloží raw XML + parsované záznamy
+4. Placeholdery pro odbornosti bez lékaře ukládá s `ma_lekare=0`
-→ **Zjistit heslo** pod kterým byl exportován (nebo exportovat znovu z Windows certstore).
-
----
-
-## Testovací skript
-
-`u:\ordinaceprojekt\Insurance\KdoJeLékař\_test_temp.py`
-Dotáže se na RC `7309208104`, odbornosti 001+002+014, vypíše raw XML i parsovaný výsledek bez zápisu do DB.
-Aktuálně nastavený na `MBQualifiedCert.pfx` — po zjištění hesla přepnout na správný certifikát.
+### Knihovny
+- `Knihovny/vzpb2b_client.py` → metody `registrace_lekare()` a `parse_registrace_lekare()`
+- `Knihovny/medicus_db.py` → `get_active_registered_patients()` (opraveno 29. 4. 2026)
+- `Knihovny/mysql_db.py` → `connect_mysql()`
---
## Plán dalšího postupu
-1. **Zjistit heslo k `ICAPublicMBdo16JAN2027.pfx`** (nebo exportovat nový .pfx z Windows certstore)
-2. Ověřit funkčnost — spustit `_test_temp.py` s funkčním certifikátem
-3. Vytvořit produkční skript v tomto adresáři — batch zpracování všech pacientů z Medicus KAR
-4. Navrhnout cílovou MySQL tabulku `vzp_registrace_lekari` (nebo přidat sloupce do existující `vzp_registrace`)
+1. ~~Certifikát~~ — vyřešeno, `picka.pfx` / `Vlado7309208104+`
+2. ~~Ověřit funkčnost~~ — hotovo, HTTP 200 s daty
+3. ~~Produkční skript~~ — hotovo, `kdojelekar_tydenni.py`
+4. ~~MySQL tabulky~~ — hotovo, `vzp_registrace_lekari` + `vzp_registrace_raw`
+5. Naplánovat týdenní spouštění (Windows Task Scheduler nebo Claude schedule)
+6. Zvážit detekci změn lékaře (analogie zlomů u StavPojisteni) — zatím není v plánu
diff --git a/Insurance/KdoJeLékař/_test_no_odb.py b/Insurance/KdoJeLékař/_test_no_odb.py
new file mode 100644
index 0000000..3941dd5
--- /dev/null
+++ b/Insurance/KdoJeLékař/_test_no_odb.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import sys, requests
+sys.stdout.reconfigure(encoding='utf-8')
+from requests_pkcs12 import Pkcs12Adapter
+from datetime import date
+import xml.etree.ElementTree as ET
+
+ENDPOINT = "https://prod.b2b.vzp.cz/B2BProxy/HttpProxy/RegistracePojistencePZSB2B"
+PFX_PATH = r"u:\ordinaceprojekt\Insurance\Certificates\picka.pfx"
+PFX_PASS = "Vlado7309208104+"
+NS = {
+ "soap": "http://schemas.xmlsoap.org/soap/envelope/",
+ "rp": "http://xmlns.gemsystem.cz/B2B/RegistracePojistencePZSB2B/1",
+}
+
+envelope = """
+
+
+
+ 7309208104
+ 2026-04-29
+
+
+"""
+
+session = requests.Session()
+session.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_PATH, pkcs12_password=PFX_PASS))
+resp = session.post(ENDPOINT, data=envelope.encode("utf-8"),
+ headers={"Content-Type": "text/xml; charset=utf-8", "SOAPAction": "process"},
+ timeout=30, verify=True)
+
+print(f"HTTP: {resp.status_code}")
+root = ET.fromstring(resp.text)
+items = root.findall(".//rp:odbornost", NS)
+print(f"Pocet odbornosti: {len(items)}")
+for i, it in enumerate(items):
+ print(f"\n--- odbornost #{i+1} ---")
+ print(ET.tostring(it, encoding="unicode"))
+
+st = root.find(".//rp:stavVyrizeniPozadavku", NS)
+print(f"stav: {st.text if st is not None else '?'}")
diff --git a/Insurance/KdoJeLékař/_test_temp.py b/Insurance/KdoJeLékař/_test_temp.py
index 159fa10..84150f8 100644
--- a/Insurance/KdoJeLékař/_test_temp.py
+++ b/Insurance/KdoJeLékař/_test_temp.py
@@ -9,26 +9,22 @@ import xml.etree.ElementTree as ET
from datetime import date
ENDPOINT = "https://prod.b2b.vzp.cz/B2BProxy/HttpProxy/RegistracePojistencePZSB2B"
-PFX_PATH = r"u:\ordinaceprojekt\Insurance\Certificates\MBQualifiedCert.pfx"
-PFX_PASS = "Vlado7309208104++"
+PFX_PATH = r"u:\ordinaceprojekt\Insurance\Certificates\picka.pfx"
+PFX_PASS = "Vlado7309208104+"
RC = "7309208104"
K_DATU = date.today().isoformat()
-ODBORNOSTI = ["001", "002", "014"] # VPL, gynekologie, stomatologie
-
NS = {
"soap": "http://schemas.xmlsoap.org/soap/envelope/",
"rp": "http://xmlns.gemsystem.cz/B2B/RegistracePojistencePZSB2B/1",
}
-odb_xml = "".join(f"{k}" for k in ODBORNOSTI)
envelope = f"""
{RC}
{K_DATU}
- {odb_xml}
"""
diff --git a/Insurance/KdoJeLékař/kdojelekar_tydenni.py b/Insurance/KdoJeLékař/kdojelekar_tydenni.py
new file mode 100644
index 0000000..8c82944
--- /dev/null
+++ b/Insurance/KdoJeLékař/kdojelekar_tydenni.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+kdojelekar_tydenni.py
+======================
+Projde aktivně registrované pacienty z Medicus a pro každého zjistí
+registrujícího lékaře u VZP (odbornosti 001, 002, 014).
+Výsledky uloží do MySQL tabulky vzp_registrace_lekari.
+
+Spouštět týdně. Mezi dotazy 2s prodleva (API_DELAY).
+
+TEST_MODE = True → zpracuje jen 3 náhodné pacienty, bez zápisu do DB.
+TEST_MODE = False → produkční běh, zapíše vše.
+"""
+
+import sys
+import time
+import random
+from pathlib import Path
+from datetime import date
+
+PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
+sys.path.insert(0, str(PROJECT_ROOT))
+
+from Knihovny.vzpb2b_client import VZPB2BClient
+from Knihovny.mysql_db import connect_mysql
+from Knihovny.medicus_db import get_medicus_db
+
+# ── KONFIGURACE ───────────────────────────────────────────────────────────────
+
+API_PAUSE = 2 # sekundy mezi VZP dotazy
+
+TEST_MODE = True # False = produkční běh
+
+PFX_PATH = Path(__file__).resolve().parent.parent / "Certificates" / "picka.pfx"
+PFX_PASS = "Vlado7309208104+"
+ODBORNOSTI = ["001", "002", "014"] # VPL, gynekologie, stomatologie
+
+TODAY = date.today()
+
+# ── INIT ──────────────────────────────────────────────────────────────────────
+
+vzp = VZPB2BClient("prod", str(PFX_PATH), PFX_PASS)
+mysql = connect_mysql()
+
+# ── PACIENTI Z MEDICUS ────────────────────────────────────────────────────────
+
+medicus = get_medicus_db()
+pacienti = medicus.get_active_registered_patients(as_dict=True)
+medicus.close()
+
+print(f"Aktivně registrovaných pacientů: {len(pacienti)}")
+
+if TEST_MODE:
+ pacienti = random.sample(pacienti, min(3, len(pacienti)))
+ print(f"TEST MODE — zpracuji {len(pacienti)} náhodné pacienty, BEZ zápisu do DB\n")
+else:
+ # Načti RC která už dnes mají uložený raw XML — ty přeskočíme
+ with mysql.cursor() as cur:
+ cur.execute("SELECT rc FROM vzp_registrace_raw WHERE k_datu = %s", (TODAY,))
+ hotove = {row[0] for row in cur.fetchall()}
+ pacienti = [p for p in pacienti if (p.get("rodcis") or "").strip() not in hotove]
+ print(f"PRODUKČNÍ běh — k_datu={TODAY}, zbývá zpracovat: {len(pacienti)} pacientů"
+ f" ({len(hotove)} již hotovo dnes)\n")
+
+# ── BATCH ─────────────────────────────────────────────────────────────────────
+
+call_count = 0
+
+for i, pac in enumerate(pacienti):
+ rc = (pac.get("rodcis") or "").strip()
+ prijmeni = (pac.get("prijmeni") or "").strip()
+ jmeno = (pac.get("jmeno") or "").strip()
+
+ if not rc:
+ continue
+
+ if call_count > 0:
+ time.sleep(API_PAUSE)
+ call_count += 1
+
+ print(f"[{i+1}/{len(pacienti)}] {prijmeni} {jmeno} ({rc}) ...", end=" ", flush=True)
+
+ try:
+ xml = vzp.registrace_lekare(rc=rc, k_datu=TODAY.isoformat(), odbornosti=ODBORNOSTI)
+ zaznamy = vzp.parse_registrace_lekare(xml)
+ except Exception as e:
+ print(f"CHYBA: {e}")
+ continue
+
+ print(f"{len(zaznamy)} lékař(ů)")
+
+ for z in zaznamy:
+ print(f" {z['kod_odbornosti']}: {z['nazev_lekare']} / {z['nazev_zzz']}"
+ f" [{z['datum_zahajeni']} – {z['datum_ukonceni']}]")
+
+ # Pokud VZP nevrátila žádného lékaře pro některou odbornost, uložíme placeholder
+ nalezene_kody = {z["kod_odbornosti"] for z in zaznamy}
+ for kod in ODBORNOSTI:
+ if kod not in nalezene_kody:
+ zaznamy.append({
+ "ma_lekare": False,
+ "kod_odbornosti": kod,
+ "nazev_odbornosti": None,
+ "ICZ": None, "ICP": None,
+ "nazev_lekare": None, "nazev_zzz": None,
+ "poj_kod": None, "poj_zkratka": None,
+ "datum_registrace": None, "datum_zahajeni": None, "datum_ukonceni": None,
+ "stav_vyrizeni": None,
+ })
+ print(f" {kod}: (žádný lékař)")
+
+ if TEST_MODE:
+ continue
+
+ with mysql.cursor() as cur:
+ cur.execute("""
+ INSERT INTO vzp_registrace_raw (rc, k_datu, raw_xml)
+ VALUES (%s, %s, %s)
+ ON DUPLICATE KEY UPDATE raw_xml=VALUES(raw_xml)
+ """, (rc, TODAY, xml))
+
+ with mysql.cursor() as cur:
+ for z in zaznamy:
+ cur.execute("""
+ INSERT INTO vzp_registrace_lekari
+ (rc, prijmeni, jmeno, k_datu, kod_odbornosti, ma_lekare,
+ ICZ, ICP, nazev_lekare, nazev_zzz,
+ poj_kod, poj_zkratka,
+ datum_registrace, datum_zahajeni, datum_ukonceni,
+ stav_vyrizeni)
+ VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
+ ON DUPLICATE KEY UPDATE
+ prijmeni=VALUES(prijmeni), jmeno=VALUES(jmeno),
+ ma_lekare=VALUES(ma_lekare),
+ ICZ=VALUES(ICZ), ICP=VALUES(ICP),
+ nazev_lekare=VALUES(nazev_lekare), nazev_zzz=VALUES(nazev_zzz),
+ poj_kod=VALUES(poj_kod), poj_zkratka=VALUES(poj_zkratka),
+ datum_registrace=VALUES(datum_registrace),
+ datum_zahajeni=VALUES(datum_zahajeni),
+ datum_ukonceni=VALUES(datum_ukonceni),
+ stav_vyrizeni=VALUES(stav_vyrizeni)
+ """, (
+ rc, prijmeni, jmeno, TODAY, z["kod_odbornosti"], 1 if z["ma_lekare"] else 0,
+ z["ICZ"], z["ICP"], z["nazev_lekare"], z["nazev_zzz"],
+ z["poj_kod"], z["poj_zkratka"],
+ z["datum_registrace"], z["datum_zahajeni"], z["datum_ukonceni"],
+ z["stav_vyrizeni"],
+ ))
+
+print(f"\nHotovo. VZP dotazů: {call_count}")
+if TEST_MODE:
+ print("(TEST MODE — nic nebylo zapsáno do DB)")
+
+mysql.close()
diff --git a/Knihovny/medicus_db.py b/Knihovny/medicus_db.py
index 6ca2fb6..6c58171 100644
--- a/Knihovny/medicus_db.py
+++ b/Knihovny/medicus_db.py
@@ -70,13 +70,21 @@ class MedicusDB:
kar.prijmeni,
kar.jmeno,
kar.poj
- FROM registr
- JOIN kar ON registr.idpac = kar.idpac
- WHERE registr.datum_zruseni IS NULL
- AND registr.priznak IN ('A','D','V')
+ FROM kar
+ WHERE kar.vyrazen = 'N'
AND kar.rodcis IS NOT NULL
AND kar.rodcis <> ''
- AND kar.vyrazen <> 'A'
+ AND EXISTS (
+ SELECT r.id FROM registr r
+ JOIN icp i ON r.idicp = i.idicp
+ WHERE r.idpac = kar.idpac
+ AND r.datum <= CURRENT_DATE
+ AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= CURRENT_DATE)
+ AND r.priznak IN ('V','D','A')
+ AND i.icp = '09305001'
+ AND i.odb = '001'
+ )
+ ORDER BY kar.prijmeni, kar.rodcis
"""
if as_dict:
return self.query_dict(sql)
diff --git a/Knihovny/vzpb2b_client.py b/Knihovny/vzpb2b_client.py
index a8ea67f..1d31f2b 100644
--- a/Knihovny/vzpb2b_client.py
+++ b/Knihovny/vzpb2b_client.py
@@ -162,6 +162,96 @@ class VZPB2BClient:
print("HTTP:", resp.status_code)
return resp.text
+ def registrace_lekare(self, rc: str, k_datu: str = None,
+ odbornosti: list = None) -> str:
+ """
+ Calls RegistracePojistencePZSB2B — vrátí registrující lékaře pojištěnce.
+ odbornosti: seznam kódů, např. ["001","002","014"]. None = bez filtru (vrátí vše).
+ """
+ service = "RegistracePojistencePZSB2B"
+ endpoint = self._build_endpoint(service)
+
+ if not k_datu:
+ k_datu = date.today().isoformat()
+
+ ns = "http://xmlns.gemsystem.cz/B2B/RegistracePojistencePZSB2B/1"
+ odb_xml = ""
+ if odbornosti:
+ kody = "".join(f"{k}"
+ for k in odbornosti)
+ odb_xml = f"{kody}"
+
+ soap = f"""
+
+
+
+ {rc}
+ {k_datu}
+ {odb_xml}
+
+
+"""
+
+ resp = self.session.post(
+ endpoint,
+ data=soap.encode("utf-8"),
+ headers={"Content-Type": "text/xml; charset=utf-8", "SOAPAction": "process"},
+ timeout=30,
+ )
+ return resp.text
+
+ def parse_registrace_lekare(self, xml_text: str) -> list[dict]:
+ """
+ Parsuje odpověď RegistracePojistencePZSB2B.
+ Vrátí seznam diktů — jeden na odbornost (i prázdné = ma_lekare=False).
+ """
+ import xml.etree.ElementTree as ET
+
+ NS = {
+ "soap": "http://schemas.xmlsoap.org/soap/envelope/",
+ "rp": "http://xmlns.gemsystem.cz/B2B/RegistracePojistencePZSB2B/1",
+ }
+
+ root = ET.fromstring(xml_text)
+ stav_el = root.find(".//rp:stavVyrizeniPozadavku", NS)
+ stav_vyrizeni = stav_el.text.strip() if stav_el is not None and stav_el.text else None
+
+ # Jen vnější elementy (ty s ICZ), ne vnořené subelementy
+ results = []
+ for it in root.findall(".//rp:seznamOdbornosti/rp:odbornost", NS):
+ def g(tag):
+ el = it.find(f"rp:{tag}", NS)
+ return el.text.strip() if el is not None and el.text else None
+
+ odb = it.find("rp:odbornost", NS)
+
+ if odb is not None:
+ # Záznam s lékařem
+ kod = odb.find("rp:kod", NS)
+ naz = odb.find("rp:nazev", NS)
+ poj = it.find("rp:zdravotniPojistovna", NS)
+ results.append({
+ "ma_lekare": True,
+ "kod_odbornosti": kod.text.strip() if kod is not None and kod.text else None,
+ "nazev_odbornosti": naz.text.strip() if naz is not None and naz.text else None,
+ "ICZ": g("ICZ"),
+ "ICP": g("ICP"),
+ "nazev_lekare": g("nazevICP"),
+ "nazev_zzz": g("nazevSZZ"),
+ "poj_kod": poj.find("rp:kod", NS).text.strip() if poj is not None and poj.find("rp:kod", NS) is not None else None,
+ "poj_zkratka": poj.find("rp:zkratka", NS).text.strip() if poj is not None and poj.find("rp:zkratka", NS) is not None else None,
+ "datum_registrace": g("datumRegistrace"),
+ "datum_zahajeni": g("datumZahajeni"),
+ "datum_ukonceni": g("datumUkonceni"),
+ "stav_vyrizeni": stav_vyrizeni,
+ })
+ else:
+ # Prázdný placeholder — pacient nemá lékaře v této odbornosti
+ # (VZP vrací element bez ICZ/ICP — ignorujeme, zaznamená skript sám)
+ pass
+
+ return results
+
def parse_stav_pojisteni(self, xml_text: str):
"""
Parses stavPojisteniB2B SOAP response into a Python dict.