220 lines
8.6 KiB
Python
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ů.")
|