Files
ordinaceprojekt/Insurance/SeznamPojistencu/06_nasledny_lekar.py
T
Vladimir Buzalka 371eed9971 notebookvb
2026-05-03 07:02:22 +02:00

220 lines
8.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys as _sys
_sys.stdout.reconfigure(encoding="utf-8", errors="replace")
_sys.stderr.reconfigure(encoding="utf-8", errors="replace")
"""
06_nasledny_lekar.py
====================
Pro všechny ukončené pacienty (103) se dotáže VZP ke dni ukonceni+1
na jejich nového praktického lékaře (odbornost 001).
Výsledek je jeden ze tří stavů:
nenalezen → pacient u VZP neexistuje (zemřel / přestal být pojištěný)
bez_lekare → pacient existuje, ale nemá GP (dosud se nepřehlásil)
prehlasil → přehlásil se k novému lékaři (ukládáme ICP, jméno, datum)
Ukládá do tabulky seznam_pojistencu_nasledny_lekar.
Přeskočí pacienty, kteří tam už jsou (resumovatelný běh).
"""
import sys
import time
import xml.etree.ElementTree as ET
from datetime import date, timedelta
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "Knihovny"))
from mysql_db import connect_mysql
from vzpb2b_client import VZPB2BClient
PFX_PATH = str(Path(__file__).resolve().parents[1] / "Certificates" / "picka.pfx")
PFX_PASSWORD = "Vlado7309208104+"
ICZ = "09305000"
API_PAUSE = 2
CREATE_SQL = """
CREATE TABLE IF NOT EXISTS seznam_pojistencu_nasledny_lekar (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
cip VARCHAR(12) NOT NULL,
prijmeni VARCHAR(60) NOT NULL,
jmeno VARCHAR(40) NOT NULL,
datum_ukonceni DATE NOT NULL COMMENT 'Datum ukončení u nás',
datum_dotazu DATE NOT NULL COMMENT 'Dotaz k datu ukonceni+1',
stav_vzp VARCHAR(20) NOT NULL COMMENT 'nenalezen / bez_lekare / prehlasil',
stav_vyrizeni VARCHAR(10) NULL COMMENT 'stavVyrizeniPozadavku z VZP',
novy_icp VARCHAR(20) NULL,
novy_icz VARCHAR(20) NULL,
novy_nazev VARCHAR(200) NULL COMMENT 'nazevSZZ — jméno lékaře',
novy_ordinace VARCHAR(200) NULL COMMENT 'nazevICP — název ordinace',
datum_prehlaseni DATE NULL COMMENT 'datumRegistrace u nového lékaře',
dotazeno_dne DATE NOT NULL,
UNIQUE KEY uq_cip (cip)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='Stav pojištěnce ke dni ukončení registrace u naší ordinace';
"""
NS = "http://xmlns.gemsystem.cz/B2B/RegistracePojistencePZSB2B/1"
def parse_nasledny(xml_text: str) -> dict:
"""
Vrátí dict s klíči: stav_vzp, stav_vyrizeni, novy_icp, novy_icz,
novy_nazev, novy_ordinace, datum_prehlaseni.
"""
try:
root = ET.fromstring(xml_text)
except ET.ParseError:
return {"stav_vzp": "chyba_xml", "stav_vyrizeni": None,
"novy_icp": None, "novy_icz": None, "novy_nazev": None,
"novy_ordinace": None, "datum_prehlaseni": None}
def find(el, tag):
e = el.find(f"{{{NS}}}{tag}")
return e.text.strip() if e is not None and e.text else None
stav_vyrizeni = find(root, "stavVyrizeniPozadavku")
# Hledám odbornost 001 s jiným lékařem
odbornosti = root.findall(f".//{{{NS}}}odbornost")
for odb in odbornosti:
# Vnější element — má ICZ
icz = find(odb, "ICZ")
icp = find(odb, "ICP")
if not icp:
continue
# Ověřím odbornost (vnořený subelement)
sub = odb.find(f"{{{NS}}}odbornost")
if sub is None:
continue
kod = find(sub, "kod")
if kod != "001":
continue
# Nalezen nový GP
dr = date.fromisoformat(find(odb, "datumRegistrace")) \
if find(odb, "datumRegistrace") else None
return {
"stav_vzp": "prehlasil",
"stav_vyrizeni": stav_vyrizeni,
"novy_icp": icp,
"novy_icz": icz,
"novy_nazev": find(odb, "nazevSZZ"),
"novy_ordinace": find(odb, "nazevICP"),
"datum_prehlaseni": dr,
}
# Žádná odbornost 001 nenalezena
if stav_vyrizeni == "0":
stav = "nenalezen"
elif stav_vyrizeni == "1":
stav = "bez_lekare"
else:
# Zkusím ještě — pokud jsou nějaké záznamy ale ne 001, je to bez_lekare
stav = "nenalezen" if not odbornosti else "bez_lekare"
return {"stav_vzp": stav, "stav_vyrizeni": stav_vyrizeni,
"novy_icp": None, "novy_icz": None, "novy_nazev": None,
"novy_ordinace": None, "datum_prehlaseni": None}
# ── Načtení ukončených pacientů ───────────────────────────────────────────────
conn = connect_mysql()
cur = conn.cursor()
cur.execute(CREATE_SQL)
# Ukončení z vzp_registrace_lekari
cur.execute("""
SELECT r.rc, r.prijmeni, r.jmeno, r.datum_ukonceni
FROM vzp_registrace_lekari r
INNER JOIN (
SELECT rc, MAX(k_datu) mk
FROM vzp_registrace_lekari
WHERE kod_odbornosti='001' AND ICP='09305001' AND ma_lekare=1
GROUP BY rc
) l ON r.rc=l.rc AND r.k_datu=l.mk
WHERE r.kod_odbornosti='001' AND r.ICP='09305001'
AND r.datum_ukonceni < '3000-01-01' AND r.datum_ukonceni < CURDATE()
""")
pacienti = [(r[0], r[1] or "", r[2] or "", r[3]) for r in cur.fetchall()]
# Doplním ze zlomů (13 nespárovaných)
cur.execute("""
SELECT cip, prijmeni, jmeno, zlom_datum
FROM seznam_pojistencu_zlomy
WHERE stav='ukončen' AND zlom_datum IS NOT NULL AND zlom_datum < CURDATE()
""")
for r in cur.fetchall():
if r[0] not in {p[0] for p in pacienti}:
pacienti.append((r[0], r[1], r[2], r[3]))
# Přeskočím již zpracované
cur.execute("SELECT cip FROM seznam_pojistencu_nasledny_lekar")
hotovi = {r[0] for r in cur.fetchall()}
ke_zpracovani = [(c, p, j, d) for c, p, j, d in pacienti if c not in hotovi]
print(f"Ukončených celkem: {len(pacienti)}")
print(f"Již zpracováno: {len(hotovi)}")
print(f"Ke zpracování: {len(ke_zpracovani)}")
if not ke_zpracovani:
print("Vše již zpracováno.")
cur.close(); conn.close(); sys.exit(0)
vzp = VZPB2BClient("prod", PFX_PATH, PFX_PASSWORD, icz=ICZ)
# ── Hlavní smyčka ─────────────────────────────────────────────────────────────
print()
sirka = max(len(f"{p} {j}") for _, p, j, _ in ke_zpracovani) + 2
for i, (cip, pri, jme, du) in enumerate(ke_zpracovani, 1):
datum_dotazu = du + timedelta(days=1)
jmeno_str = f"{pri} {jme}"
print(f"[{i:>3}/{len(ke_zpracovani)}] {jmeno_str:<{sirka}} ({cip}) k {datum_dotazu}", end=" ", flush=True)
try:
xml = vzp.registrace_lekare(cip, datum_dotazu.isoformat(), odbornosti=["001"])
time.sleep(API_PAUSE)
vysl = parse_nasledny(xml)
except Exception as e:
print(f"CHYBA: {e}")
vysl = {"stav_vzp": "chyba", "stav_vyrizeni": str(e),
"novy_icp": None, "novy_icz": None, "novy_nazev": None,
"novy_ordinace": None, "datum_prehlaseni": None}
# Výpis
stav = vysl["stav_vzp"]
if stav == "prehlasil":
print(f"→ přehlásil se: {vysl['novy_nazev']} (ICP {vysl['novy_icp']}, od {vysl['datum_prehlaseni']})")
elif stav == "bez_lekare":
print("→ bez nového lékaře")
elif stav == "nenalezen":
print("→ nenalezen (zemřel / nepojištěný)")
else:
print(f"{stav}")
cur.execute("""
INSERT INTO seznam_pojistencu_nasledny_lekar
(cip, prijmeni, jmeno, datum_ukonceni, datum_dotazu, stav_vzp,
stav_vyrizeni, novy_icp, novy_icz, novy_nazev, novy_ordinace,
datum_prehlaseni, dotazeno_dne)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON DUPLICATE KEY UPDATE
datum_ukonceni=VALUES(datum_ukonceni),
datum_dotazu=VALUES(datum_dotazu),
stav_vzp=VALUES(stav_vzp), stav_vyrizeni=VALUES(stav_vyrizeni),
novy_icp=VALUES(novy_icp), novy_icz=VALUES(novy_icz),
novy_nazev=VALUES(novy_nazev), novy_ordinace=VALUES(novy_ordinace),
datum_prehlaseni=VALUES(datum_prehlaseni),
dotazeno_dne=VALUES(dotazeno_dne)
""", (cip, pri, jme, du, datum_dotazu, stav,
vysl["stav_vyrizeni"], vysl["novy_icp"], vysl["novy_icz"],
vysl["novy_nazev"], vysl["novy_ordinace"], vysl["datum_prehlaseni"],
date.today()))
cur.close()
conn.close()
# ── Souhrn ────────────────────────────────────────────────────────────────────
print(f"\nHotovo. Zpracováno {len(ke_zpracovani)} pacientů.")