notebookvb
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
#!/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")
|
||||
"""
|
||||
04_najdi_zlomy.py
|
||||
=================
|
||||
Pro pacienty z seznam_pojistencu_davky, kteří NEMAJÍ záznam v vzp_registrace_lekari
|
||||
(skript kdojelekar je nezachytil), najde bod zlomu registrace u naší ambulance.
|
||||
|
||||
Algoritmus:
|
||||
1. Dotaz VZP dnes — je pacient stále registrován u nás (ICP=09305001)?
|
||||
ANO → datum_ukonceni z odpovědi = výsledek
|
||||
2. NE → hledáme rokem dozadu (od dnes, −1 rok, −2 roky …)
|
||||
dokud nenajdeme rok kdy BYL registrován → tím ohraničíme interval [lo, hi]
|
||||
3. V intervalu [lo, hi] binární hledání na den přesně
|
||||
(nebo pokud datum_ukonceni z VZP odpovědi není 3000, použijeme ho přímo)
|
||||
|
||||
Výsledek se uloží do tabulky seznam_pojistencu_zlomy a vytiskne na konzoli.
|
||||
"""
|
||||
|
||||
import time
|
||||
import sys
|
||||
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
|
||||
|
||||
# ── Konfigurace ───────────────────────────────────────────────────────────────
|
||||
PFX_PATH = str(Path(__file__).resolve().parents[1] / "Certificates" / "picka.pfx")
|
||||
PFX_PASSWORD = "Vlado7309208104+"
|
||||
ICZ = "09305000"
|
||||
NASA_ICP = "09305001"
|
||||
API_PAUSE = 2 # sekundy mezi VZP dotazy
|
||||
|
||||
CREATE_SQL = """
|
||||
CREATE TABLE IF NOT EXISTS seznam_pojistencu_zlomy (
|
||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
cip VARCHAR(12) NOT NULL,
|
||||
prijmeni VARCHAR(30) NOT NULL,
|
||||
jmeno VARCHAR(24) NOT NULL,
|
||||
posledni_davka DATE NOT NULL COMMENT 'Poslední měsíc kdy byl v dávce',
|
||||
zlom_datum DATE NULL COMMENT 'Poslední den registrace u nás (NULL=stále aktivní)',
|
||||
zlom_zdroj VARCHAR(60) NULL COMMENT 'Jak byl zlom určen',
|
||||
stav VARCHAR(20) NOT NULL COMMENT 'aktivní / ukončen / nenalezen',
|
||||
dotazeno_dne DATE NOT NULL,
|
||||
UNIQUE KEY uq_cip (cip)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Zlomy registrace pro pacienty bez záznamu v kdojelekar';
|
||||
"""
|
||||
|
||||
# ── VZP klient ────────────────────────────────────────────────────────────────
|
||||
vzp = VZPB2BClient("prod", PFX_PATH, PFX_PASSWORD, icz=ICZ)
|
||||
|
||||
|
||||
def je_registrovan(rc: str, k_datu: date) -> tuple[bool, date | None]:
|
||||
"""
|
||||
Vrátí (registrován_u_nas: bool, datum_ukonceni: date|None).
|
||||
datum_ukonceni = None pokud nelze parsovat nebo pacient není u nás.
|
||||
"""
|
||||
xml = vzp.registrace_lekare(rc, k_datu.isoformat(), odbornosti=["001"])
|
||||
time.sleep(API_PAUSE)
|
||||
try:
|
||||
zaznamy = vzp.parse_registrace_lekare(xml)
|
||||
except Exception as e:
|
||||
print(f" [CHYBA parsování] {e}")
|
||||
return False, None
|
||||
|
||||
for z in zaznamy:
|
||||
if z.get("ma_lekare") and z.get("ICP") == NASA_ICP and z.get("kod_odbornosti") == "001":
|
||||
du_str = z.get("datum_ukonceni")
|
||||
try:
|
||||
du = date.fromisoformat(du_str) if du_str else None
|
||||
except ValueError:
|
||||
du = None
|
||||
return True, du
|
||||
|
||||
return False, None
|
||||
|
||||
|
||||
def najdi_zlom(rc: str, posledni_davka: date) -> tuple[date | None, str, str]:
|
||||
"""
|
||||
Vrátí (zlom_datum, zlom_zdroj, stav).
|
||||
zlom_datum = poslední den kdy byl registrován (None = stále aktivní).
|
||||
"""
|
||||
today = date.today()
|
||||
|
||||
# ── Krok 1: dotaz dnes ────────────────────────────────────────────────────
|
||||
print(f" [dnes {today}]", end=" ", flush=True)
|
||||
reg, du = je_registrovan(rc, today)
|
||||
|
||||
if reg:
|
||||
if du and du.year < 3000:
|
||||
print(f"registrován, ukončení {du}")
|
||||
return du, "VZP datum_ukonceni (dnes)", "ukončen"
|
||||
else:
|
||||
print("registrován, bez data ukončení → stále aktivní")
|
||||
return None, "VZP dnes aktivní", "aktivní"
|
||||
|
||||
print("NENÍ registrován")
|
||||
|
||||
# ── Krok 2: hledání po rocích dozadu ─────────────────────────────────────
|
||||
# lo = víme, že tam BYL (posledni_davka)
|
||||
# hi = víme, že tam NENÍ (today)
|
||||
lo: date = posledni_davka
|
||||
hi: date = today
|
||||
|
||||
probe = today.replace(year=today.year - 1)
|
||||
while probe >= posledni_davka:
|
||||
print(f" [rok {probe}]", end=" ", flush=True)
|
||||
reg_p, du_p = je_registrovan(rc, probe)
|
||||
if reg_p:
|
||||
lo = probe
|
||||
print(f"registrován")
|
||||
if du_p and du_p.year < 3000:
|
||||
print(f" → datum_ukonceni z VZP: {du_p}")
|
||||
return du_p, f"VZP datum_ukonceni (dotaz {probe})", "ukončen"
|
||||
break
|
||||
else:
|
||||
hi = probe
|
||||
print("není")
|
||||
try:
|
||||
probe = probe.replace(year=probe.year - 1)
|
||||
except ValueError:
|
||||
break
|
||||
else:
|
||||
# Ani v posledni_davka není registrován — neobvyklé
|
||||
print(f" ! Ani k datu {posledni_davka} není registrován — zkouším přímo")
|
||||
reg_lo, du_lo = je_registrovan(rc, posledni_davka)
|
||||
if not reg_lo:
|
||||
return None, "nenalezen ani k datu poslední dávky", "nenalezen"
|
||||
lo = posledni_davka
|
||||
if du_lo and du_lo.year < 3000:
|
||||
return du_lo, f"VZP datum_ukonceni ({posledni_davka})", "ukončen"
|
||||
|
||||
# ── Krok 3: binární hledání v intervalu [lo, hi] ─────────────────────────
|
||||
print(f" Binární hledání: {lo} … {hi}")
|
||||
iterace = 0
|
||||
while (hi - lo).days > 1:
|
||||
iterace += 1
|
||||
mid = lo + timedelta(days=(hi - lo).days // 2)
|
||||
print(f" [{iterace}. iterace: {mid}]", end=" ", flush=True)
|
||||
reg_m, du_m = je_registrovan(rc, mid)
|
||||
if reg_m:
|
||||
lo = mid
|
||||
print("registrován")
|
||||
if du_m and du_m.year < 3000:
|
||||
print(f" → datum_ukonceni z VZP: {du_m}")
|
||||
return du_m, f"VZP datum_ukonceni (binární {mid})", "ukončen"
|
||||
else:
|
||||
hi = mid
|
||||
print("není")
|
||||
|
||||
print(f" → Zlom: poslední den registrace = {lo}")
|
||||
return lo, f"binární hledání ({iterace} kroků)", "ukončen"
|
||||
|
||||
|
||||
# ── Načtení pacientů ──────────────────────────────────────────────────────────
|
||||
|
||||
conn = connect_mysql()
|
||||
cur = conn.cursor()
|
||||
cur.execute(CREATE_SQL)
|
||||
|
||||
# Unikátní CIP v seznamu (VZP, pojišťovna 111)
|
||||
cur.execute("SELECT DISTINCT cip FROM seznam_pojistencu_davky WHERE pojistovna='111'")
|
||||
vsechny_cip = {r[0] for r in cur.fetchall()}
|
||||
|
||||
# CIP které jsou v registrace_lekari (u nás, odb 001)
|
||||
cur.execute("""
|
||||
SELECT DISTINCT rc FROM vzp_registrace_lekari
|
||||
WHERE kod_odbornosti='001' AND ICP='09305001' AND ma_lekare=1
|
||||
""")
|
||||
zname_cip = {r[0] for r in cur.fetchall()}
|
||||
|
||||
# Nespárované
|
||||
nesparovane_cip = vsechny_cip - zname_cip
|
||||
|
||||
# Doplním jméno a posledni_davka
|
||||
cur.execute("""
|
||||
SELECT cip, MIN(prijmeni), MIN(jmeno),
|
||||
MAX(DATE(CONCAT(davka_rok, '-', LPAD(davka_mesic,2,'0'), '-01')))
|
||||
FROM seznam_pojistencu_davky
|
||||
WHERE pojistovna='111'
|
||||
GROUP BY cip
|
||||
""")
|
||||
info = {r[0]: (r[1], r[2], r[3]) for r in cur.fetchall()}
|
||||
|
||||
pacienti = [
|
||||
(cip, *info[cip])
|
||||
for cip in sorted(nesparovane_cip)
|
||||
if cip in info
|
||||
]
|
||||
|
||||
print(f"Pacientů ke zpracování: {len(pacienti)}\n")
|
||||
print("=" * 70)
|
||||
|
||||
# ── Hlavní smyčka ─────────────────────────────────────────────────────────────
|
||||
|
||||
vysledky = []
|
||||
for cip, prijmeni, jmeno, posledni_davka in pacienti:
|
||||
print(f"\n{prijmeni} {jmeno} (CIP: {cip}, poslední dávka: {posledni_davka})")
|
||||
try:
|
||||
zlom, zdroj, stav = najdi_zlom(cip, posledni_davka)
|
||||
except Exception as e:
|
||||
print(f" CHYBA: {e}")
|
||||
zlom, zdroj, stav = None, f"chyba: {e}", "chyba"
|
||||
|
||||
vysledky.append((cip, prijmeni, jmeno, posledni_davka, zlom, zdroj, stav))
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO seznam_pojistencu_zlomy
|
||||
(cip, prijmeni, jmeno, posledni_davka, zlom_datum, zlom_zdroj, stav, dotazeno_dne)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
posledni_davka=VALUES(posledni_davka),
|
||||
zlom_datum=VALUES(zlom_datum),
|
||||
zlom_zdroj=VALUES(zlom_zdroj),
|
||||
stav=VALUES(stav),
|
||||
dotazeno_dne=VALUES(dotazeno_dne)
|
||||
""", (cip, prijmeni, jmeno, posledni_davka, zlom, zdroj, stav, date.today()))
|
||||
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
# ── Výsledky ──────────────────────────────────────────────────────────────────
|
||||
print("\n" + "=" * 70)
|
||||
print(f"\n{'Příjmení':<25} {'Jméno':<20} {'CIP':<12} {'Poslední dávka':<15} {'Zlom':<12} Stav")
|
||||
print("-" * 95)
|
||||
for cip, pri, jme, pd, zd, zdroj, stav in vysledky:
|
||||
zlom_str = str(zd) if zd else "—"
|
||||
print(f"{pri:<25} {jme:<20} {cip:<12} {str(pd):<15} {zlom_str:<12} {stav}")
|
||||
Reference in New Issue
Block a user