notebookvb
This commit is contained in:
@@ -0,0 +1,362 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Exportuje 151 pacientů registrovaných v Medicusu k 1.1.2025,
|
||||
u nichž VZP k tomuto datu nevykazuje registraci v odbornosti 001 u IČP 09305001.
|
||||
Výstup: Excel s komentářem a aktuálním stavem v Medicusu.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import date
|
||||
from collections import defaultdict
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
|
||||
|
||||
from Knihovny.mysql_db import connect_mysql
|
||||
import fdb, socket
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import (Font, PatternFill, Alignment, Border, Side,
|
||||
GradientFill)
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
# ── Konfigurace ────────────────────────────────────────────────────────────────
|
||||
K_DATU_HIST = "2025-01-01"
|
||||
TODAY = date.today()
|
||||
OUT_FILE = Path(__file__).resolve().parent / f"neregistrovani_vzp_20250101.xlsx"
|
||||
|
||||
POJ_NAZVY = {
|
||||
"111": "VZP",
|
||||
"201": "ČPZP",
|
||||
"205": "ČPZP (ex-OZP)",
|
||||
"207": "OZP",
|
||||
"209": "ZPŠ",
|
||||
"211": "ZPMV",
|
||||
"213": "RBP",
|
||||
}
|
||||
|
||||
# ── Barvy ──────────────────────────────────────────────────────────────────────
|
||||
BLUE_HEADER = "1F497D"
|
||||
WHITE = "FFFFFF"
|
||||
LIGHT_BLUE = "DCE6F1"
|
||||
LIGHT_GREEN = "EBF1DE"
|
||||
LIGHT_YELLOW = "FFFFC0"
|
||||
LIGHT_RED = "FCE4D6"
|
||||
LIGHT_GREY = "F2F2F2"
|
||||
ORANGE = "F4B942"
|
||||
|
||||
# ── Data z MySQL ───────────────────────────────────────────────────────────────
|
||||
mysql = connect_mysql()
|
||||
cur = mysql.cursor()
|
||||
|
||||
cur.execute("""
|
||||
SELECT rc FROM vzp_registrace_raw WHERE k_datu = %s
|
||||
AND rc NOT IN (
|
||||
SELECT rc FROM vzp_registrace_lekari
|
||||
WHERE k_datu = %s AND kod_odbornosti = '001'
|
||||
AND ICP = '09305001' AND ma_lekare = 1
|
||||
)
|
||||
""", (K_DATU_HIST, K_DATU_HIST))
|
||||
problematicke_rcs = [row[0] for row in cur.fetchall()]
|
||||
|
||||
ph = ",".join(["%s"] * len(problematicke_rcs))
|
||||
cur.execute(f"""
|
||||
SELECT rc, prijmeni, jmeno, kod_odbornosti, ma_lekare, ICP,
|
||||
nazev_lekare, nazev_zzz, poj_kod, poj_zkratka
|
||||
FROM vzp_registrace_lekari
|
||||
WHERE k_datu = %s AND rc IN ({ph}) AND kod_odbornosti = '001'
|
||||
""", (K_DATU_HIST, *problematicke_rcs))
|
||||
|
||||
vzp = {}
|
||||
for rc, prijmeni, jmeno, odb, ma, icp, nazev_lek, nazev_zzz, poj_kod, poj_zkr in cur.fetchall():
|
||||
vzp[rc] = {"prijmeni": prijmeni or "", "jmeno": jmeno or "",
|
||||
"ma_lekare": bool(ma), "ICP": icp or "",
|
||||
"nazev_lekare": nazev_lek or "", "nazev_zzz": nazev_zzz or "",
|
||||
"poj_kod": poj_kod or "", "poj_zkratka": poj_zkr or ""}
|
||||
|
||||
mysql.close()
|
||||
|
||||
# ── Data z Medicusu ────────────────────────────────────────────────────────────
|
||||
computer_name = socket.gethostname().upper()
|
||||
dsn_map = {
|
||||
"LEKAR": r"localhost:M:\medicus\data\medicus.fdb",
|
||||
"SESTRA": r"192.168.1.10:m:\medicus\data\medicus.fdb",
|
||||
"LENOVO": r"192.168.1.10:m:\medicus\data\medicus.fdb",
|
||||
}
|
||||
dsn = dsn_map.get(computer_name, r"localhost:c:\medicus 3\data\medicus.fdb")
|
||||
fb_conn = fdb.connect(dsn=dsn, user="SYSDBA", password="masterkey", charset="win1250")
|
||||
fb_cur = fb_conn.cursor()
|
||||
|
||||
# Aktuálně aktivní pacienti
|
||||
fb_cur.execute("""
|
||||
SELECT kar.rodcis FROM kar
|
||||
WHERE kar.vyrazen = 'N' AND kar.rodcis IS NOT NULL AND kar.rodcis <> ''
|
||||
AND EXISTS (
|
||||
SELECT 1 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'
|
||||
)
|
||||
""")
|
||||
aktualne_aktivni = {(row[0] or "").strip() for row in fb_cur.fetchall()}
|
||||
|
||||
# Detail všech 151 pacientů
|
||||
ph_fb = ",".join(["?" for _ in problematicke_rcs])
|
||||
fb_cur.execute(f"""
|
||||
SELECT kar.rodcis, kar.prijmeni, kar.jmeno, kar.poj, kar.vyrazen,
|
||||
r.datum, r.datum_zruseni, r.priznak
|
||||
FROM kar
|
||||
LEFT JOIN registr r ON r.idpac = kar.idpac
|
||||
LEFT JOIN icp i ON r.idicp = i.idicp AND i.icp = '09305001' AND i.odb = '001'
|
||||
WHERE kar.rodcis IN ({ph_fb})
|
||||
ORDER BY kar.rodcis, r.datum DESC
|
||||
""", problematicke_rcs)
|
||||
|
||||
medicus = {}
|
||||
for row in fb_cur.fetchall():
|
||||
rc = (row[0] or "").strip()
|
||||
if rc not in medicus:
|
||||
medicus[rc] = {
|
||||
"prijmeni": (row[1] or "").strip(),
|
||||
"jmeno": (row[2] or "").strip(),
|
||||
"poj": str(row[3] or "").strip(),
|
||||
"vyrazen": (row[4] or "").strip(),
|
||||
"reg_datum": row[5],
|
||||
"reg_datum_zruseni":row[6],
|
||||
"reg_priznak": (row[7] or "").strip(),
|
||||
}
|
||||
|
||||
fb_conn.close()
|
||||
|
||||
# ── Kategorizace ───────────────────────────────────────────────────────────────
|
||||
def kategorie(rc, vzp_row, med_row, aktivni_set):
|
||||
poj = med_row.get("poj", "") if med_row else ""
|
||||
if not vzp_row:
|
||||
if poj != "111":
|
||||
return "JINÁ POJIŠŤOVNA", "VZP neregistruje — pojištěnec jiné pojišťovny.", LIGHT_BLUE
|
||||
return "BEZ VZP ZÁZNAMU", "VZP nevrátila žádný záznam přesto, že jde o pojištěnce VZP. Pravděpodobně chybí registrace u VZP.", LIGHT_RED
|
||||
|
||||
if vzp_row["ma_lekare"]:
|
||||
return "REGISTROVÁN JINDE", f"VZP eviduje registraci u jiného lékaře: {vzp_row['nazev_zzz']} (ICP {vzp_row['ICP']}).", LIGHT_RED
|
||||
|
||||
return "BEZ LÉKAŘE U VZP", "VZP eviduje pojištěnce, ale bez registrujícího lékaře v odbornosti 001.", LIGHT_YELLOW
|
||||
|
||||
|
||||
# ── Sestavení řádků ────────────────────────────────────────────────────────────
|
||||
rows = []
|
||||
for rc in problematicke_rcs:
|
||||
vzp_row = vzp.get(rc)
|
||||
med_row = medicus.get(rc)
|
||||
aktivni = rc in aktualne_aktivni
|
||||
|
||||
prijmeni = (med_row or vzp_row or {}).get("prijmeni", "")
|
||||
jmeno = (med_row or vzp_row or {}).get("jmeno", "")
|
||||
poj_kod = med_row.get("poj", "") if med_row else (vzp_row or {}).get("poj_kod", "")
|
||||
poj_nazev = POJ_NAZVY.get(poj_kod, poj_kod)
|
||||
|
||||
med_stav = "Aktivní" if aktivni else ("Odregistrován" if med_row else "Nenalezen v Medicusu")
|
||||
reg_datum = med_row.get("reg_datum") if med_row else None
|
||||
reg_datum_zrus = med_row.get("reg_datum_zruseni") if med_row else None
|
||||
|
||||
kat, komentar, barva = kategorie(rc, vzp_row, med_row, aktualne_aktivni)
|
||||
|
||||
vzp_icp = vzp_row["ICP"] if vzp_row and vzp_row["ma_lekare"] else ""
|
||||
vzp_lek = vzp_row["nazev_zzz"] if vzp_row and vzp_row["ma_lekare"] else ""
|
||||
vzp_zzz = vzp_row["nazev_lekare"] if vzp_row and vzp_row["ma_lekare"] else ""
|
||||
|
||||
rows.append({
|
||||
"prijmeni": prijmeni,
|
||||
"jmeno": jmeno,
|
||||
"rc": rc,
|
||||
"poj_kod": poj_kod,
|
||||
"poj_nazev": poj_nazev,
|
||||
"med_stav": med_stav,
|
||||
"reg_datum": reg_datum.strftime("%d.%m.%Y") if reg_datum else "",
|
||||
"reg_zruseni": reg_datum_zrus.strftime("%d.%m.%Y") if reg_datum_zrus else "",
|
||||
"kategorie": kat,
|
||||
"komentar": komentar,
|
||||
"vzp_icp": vzp_icp,
|
||||
"vzp_lek": vzp_lek,
|
||||
"vzp_zzz": vzp_zzz,
|
||||
"barva": barva,
|
||||
})
|
||||
|
||||
rows.sort(key=lambda r: (r["kategorie"], r["prijmeni"], r["jmeno"]))
|
||||
|
||||
# ── Excel ──────────────────────────────────────────────────────────────────────
|
||||
wb = Workbook()
|
||||
|
||||
# ────────────────────────────────────────────────────────────────────────────────
|
||||
# SHEET 1: Přehled
|
||||
# ────────────────────────────────────────────────────────────────────────────────
|
||||
ws_info = wb.active
|
||||
ws_info.title = "Přehled"
|
||||
|
||||
def hdr_cell(ws, row, col, value):
|
||||
c = ws.cell(row=row, column=col, value=value)
|
||||
c.font = Font(name="Arial", bold=True, color=WHITE, size=11)
|
||||
c.fill = PatternFill("solid", fgColor=BLUE_HEADER)
|
||||
c.alignment = Alignment(horizontal="center", vertical="center")
|
||||
return c
|
||||
|
||||
def val_cell(ws, row, col, value, bold=False, bg=None):
|
||||
c = ws.cell(row=row, column=col, value=value)
|
||||
c.font = Font(name="Arial", bold=bold, size=10)
|
||||
c.alignment = Alignment(wrap_text=True, vertical="top")
|
||||
if bg:
|
||||
c.fill = PatternFill("solid", fgColor=bg)
|
||||
return c
|
||||
|
||||
ws_info.column_dimensions["A"].width = 36
|
||||
ws_info.column_dimensions["B"].width = 18
|
||||
ws_info.column_dimensions["C"].width = 60
|
||||
|
||||
# Titulek
|
||||
ws_info.merge_cells("A1:C1")
|
||||
t = ws_info["A1"]
|
||||
t.value = f"Pacienti registrovaní v Medicusu k 1. 1. 2025, ale dle VZP bez registrace u IČP 09305001"
|
||||
t.font = Font(name="Arial", bold=True, size=13, color=WHITE)
|
||||
t.fill = PatternFill("solid", fgColor=BLUE_HEADER)
|
||||
t.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||
ws_info.row_dimensions[1].height = 36
|
||||
|
||||
ws_info.merge_cells("A2:C2")
|
||||
ws_info["A2"].value = f"Vygenerováno: {TODAY.strftime('%d. %m. %Y')} | Stav v Medicusu k dnešnímu dni"
|
||||
ws_info["A2"].font = Font(name="Arial", italic=True, size=9, color="595959")
|
||||
ws_info["A2"].alignment = Alignment(horizontal="center")
|
||||
|
||||
# Souhrn počtů
|
||||
counts = defaultdict(int)
|
||||
counts_aktivni = defaultdict(int)
|
||||
for r in rows:
|
||||
counts[r["kategorie"]] += 1
|
||||
if r["med_stav"] == "Aktivní":
|
||||
counts_aktivni[r["kategorie"]] += 1
|
||||
|
||||
hdr_cell(ws_info, 4, 1, "Kategorie")
|
||||
hdr_cell(ws_info, 4, 2, "Počet pacientů")
|
||||
hdr_cell(ws_info, 4, 3, "Komentář")
|
||||
|
||||
KAT_BARVY = {
|
||||
"REGISTROVÁN JINDE": LIGHT_RED,
|
||||
"BEZ LÉKAŘE U VZP": LIGHT_YELLOW,
|
||||
"JINÁ POJIŠŤOVNA": LIGHT_BLUE,
|
||||
"BEZ VZP ZÁZNAMU": LIGHT_RED,
|
||||
}
|
||||
KAT_POPIS = {
|
||||
"REGISTROVÁN JINDE": "VZP k 1.1.2025 eviduje registraci u jiného praktického lékaře. Pacient se pravděpodobně přeregistroval jinam, aniž by byl v Medicusu odregistrován.",
|
||||
"BEZ LÉKAŘE U VZP": "VZP eviduje pojištěnce, ale v odbornosti 001 mu neeviduje žádného lékaře. Může jít o opožděné zpracování přihlášky nebo technickou chybu.",
|
||||
"JINÁ POJIŠŤOVNA": "Pacient není pojištěncem VZP — VZP o něm data nemá, proto nebylo vráceno nic. To je očekávané chování.",
|
||||
"BEZ VZP ZÁZNAMU": "VZP pojištěnec (111), ale VZP nevrátila žádný záznam. Může jít o nesprávné RC, neaktivní pojistný vztah nebo chybu v komunikaci.",
|
||||
}
|
||||
|
||||
for i, kat in enumerate(["REGISTROVÁN JINDE", "BEZ LÉKAŘE U VZP", "JINÁ POJIŠŤOVNA", "BEZ VZP ZÁZNAMU"]):
|
||||
r = 5 + i
|
||||
bg = KAT_BARVY[kat]
|
||||
val_cell(ws_info, r, 1, kat, bold=True, bg=bg)
|
||||
val_cell(ws_info, r, 2, f"{counts[kat]} ({counts_aktivni[kat]} stále aktivní)", bg=bg)
|
||||
val_cell(ws_info, r, 3, KAT_POPIS[kat], bg=bg)
|
||||
ws_info.row_dimensions[r].height = 42
|
||||
|
||||
ws_info.row_dimensions[4].height = 20
|
||||
|
||||
# Celkem
|
||||
val_cell(ws_info, 10, 1, "CELKEM", bold=True)
|
||||
val_cell(ws_info, 10, 2, f"{len(rows)} ({sum(counts_aktivni.values())} aktivní)", bold=True)
|
||||
|
||||
# Metodika
|
||||
ws_info.merge_cells("A12:C12")
|
||||
ws_info["A12"].value = "Metodika"
|
||||
ws_info["A12"].font = Font(name="Arial", bold=True, size=11, color=BLUE_HEADER)
|
||||
|
||||
metodika_text = (
|
||||
"Skript kdojelekar_20250101.py dotázal VZP B2B na registrujícího lékaře (odbornost 001) "
|
||||
"pro každého pacienta registrovaného k 1. 1. 2025 v Medicusu u IČP 09305001. "
|
||||
"Pacienti v tomto souboru jsou ti, u nichž VZP k danému datu nevrátila záznam s ICP=09305001 a ma_lekare=1. "
|
||||
"Stav v Medicusu je aktuální k dnešnímu dni (" + TODAY.strftime("%d. %m. %Y") + ")."
|
||||
)
|
||||
ws_info.merge_cells("A13:C13")
|
||||
c = ws_info["A13"]
|
||||
c.value = metodika_text
|
||||
c.font = Font(name="Arial", size=9, color="595959")
|
||||
c.alignment = Alignment(wrap_text=True, vertical="top")
|
||||
ws_info.row_dimensions[13].height = 56
|
||||
|
||||
# Doporučení
|
||||
ws_info.merge_cells("A15:C15")
|
||||
ws_info["A15"].value = "Doporučení"
|
||||
ws_info["A15"].font = Font(name="Arial", bold=True, size=11, color=BLUE_HEADER)
|
||||
|
||||
ws_info.merge_cells("A16:C16")
|
||||
c = ws_info["A16"]
|
||||
c.value = (
|
||||
"1. REGISTROVÁN JINDE — ověřit s pacientem při návštěvě, zda se přeregistroval; pokud ano, odregistrovat v Medicusu.\n"
|
||||
"2. BEZ LÉKAŘE U VZP — zkontrolovat, zda přihláška registrace byla správně odeslána a VZP ji eviduje.\n"
|
||||
"3. JINÁ POJIŠŤOVNA — tyto pacienty prověřit u příslušné pojišťovny (ČPZP, OZP…) analogickým dotazem.\n"
|
||||
"4. BEZ VZP ZÁZNAMU — ověřit správnost RC a aktivitu pojistného vztahu přímo u VZP."
|
||||
)
|
||||
c.font = Font(name="Arial", size=10)
|
||||
c.alignment = Alignment(wrap_text=True, vertical="top")
|
||||
ws_info.row_dimensions[16].height = 80
|
||||
|
||||
# ────────────────────────────────────────────────────────────────────────────────
|
||||
# SHEET 2: Data
|
||||
# ────────────────────────────────────────────────────────────────────────────────
|
||||
ws = wb.create_sheet("Pacienti")
|
||||
|
||||
COLS = [
|
||||
("Příjmení", 20),
|
||||
("Jméno", 14),
|
||||
("Rodné číslo", 14),
|
||||
("Pojišťovna", 12),
|
||||
("Stav v Medicusu\ndnes", 16),
|
||||
("Datum registrace\nv Medicusu", 16),
|
||||
("Datum zrušení\nv Medicusu", 16),
|
||||
("Kategorie VZP problému", 22),
|
||||
("Komentář", 52),
|
||||
("VZP ICP jiného lékaře", 18),
|
||||
("VZP — jméno lékaře", 28),
|
||||
("VZP — název ZZZ", 36),
|
||||
]
|
||||
|
||||
for col_idx, (header, width) in enumerate(COLS, 1):
|
||||
c = ws.cell(row=1, column=col_idx, value=header)
|
||||
c.font = Font(name="Arial", bold=True, color=WHITE, size=10)
|
||||
c.fill = PatternFill("solid", fgColor=BLUE_HEADER)
|
||||
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||
ws.column_dimensions[get_column_letter(col_idx)].width = width
|
||||
|
||||
ws.row_dimensions[1].height = 32
|
||||
ws.freeze_panes = "A2"
|
||||
|
||||
thin = Side(style="thin", color="BFBFBF")
|
||||
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
||||
|
||||
for row_idx, r in enumerate(rows, 2):
|
||||
bg = r["barva"]
|
||||
data = [
|
||||
r["prijmeni"], r["jmeno"], r["rc"], f"{r['poj_kod']} {r['poj_nazev']}",
|
||||
r["med_stav"], r["reg_datum"], r["reg_zruseni"],
|
||||
r["kategorie"], r["komentar"],
|
||||
r["vzp_icp"], r["vzp_lek"], r["vzp_zzz"],
|
||||
]
|
||||
for col_idx, value in enumerate(data, 1):
|
||||
c = ws.cell(row=row_idx, column=col_idx, value=value)
|
||||
c.font = Font(name="Arial", size=9)
|
||||
c.fill = PatternFill("solid", fgColor=bg)
|
||||
c.border = border
|
||||
c.alignment = Alignment(vertical="top", wrap_text=(col_idx in (9, 11, 12)))
|
||||
if r["med_stav"] == "Aktivní" and col_idx == 5:
|
||||
c.font = Font(name="Arial", size=9, bold=True, color="375623")
|
||||
elif r["med_stav"] != "Aktivní" and col_idx == 5:
|
||||
c.font = Font(name="Arial", size=9, color="843C0C")
|
||||
ws.row_dimensions[row_idx].height = 32
|
||||
|
||||
# AutoFilter
|
||||
ws.auto_filter.ref = f"A1:{get_column_letter(len(COLS))}1"
|
||||
|
||||
wb.save(OUT_FILE)
|
||||
print(f"Uloženo: {OUT_FILE}")
|
||||
print(f"Celkem řádků: {len(rows)}")
|
||||
Binary file not shown.
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
batch_stav0_20250101.py
|
||||
========================
|
||||
Zpracuje 50 pacientů, kteří k 1. 1. 2025 vrátili stavVyrizeniPozadavku=0
|
||||
na dotaz registrace lékaře (= VZP pojištěnce nenašla).
|
||||
|
||||
Pro každého:
|
||||
1. Dotáže VZP stavPojisteni k 2025-01-01 → uloží do vzp_stav_pojisteni.
|
||||
2. Pokud stav != '1' a != '4', binárně hledá zlom pojištění
|
||||
a uloží do vzp_sledovani_pojisteni.
|
||||
|
||||
Resumovatelný — pacienty, kteří už mají záznam v vzp_stav_pojisteni
|
||||
k 2025-01-01, přeskočí.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from datetime import date, timedelta
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from Knihovny.mysql_db import connect_mysql
|
||||
from Knihovny.vzpb2b_client import VZPB2BClient
|
||||
|
||||
# ── KONFIGURACE ───────────────────────────────────────────────────────────────
|
||||
|
||||
K_DATU = date(2025, 1, 1)
|
||||
API_DELAY = 1.5
|
||||
|
||||
PFX_PATH = Path(__file__).resolve().parent.parent / "Certificates" / "picka.pfx"
|
||||
PFX_PASSWORD = "Vlado7309208104+"
|
||||
ICZ = "00000000"
|
||||
DIC = "00000000"
|
||||
ENV = "prod"
|
||||
|
||||
# ── PACIENTI ─────────────────────────────────────────────────────────────────
|
||||
|
||||
PACIENTI = [
|
||||
("415513130", "Rohlíková", "Marie"),
|
||||
("420622031", "Hamerník", "Josef"),
|
||||
("430127082", "Anderle", "Václav"),
|
||||
("435625017", "Kafková", "Marie"),
|
||||
("436005111", "Plzáková", "Ivana"),
|
||||
("445624103", "Kloučková", "Vlasta"),
|
||||
("446116017", "Strnadová", "Dagmar"),
|
||||
("456016085", "Kubcová", "Anna"),
|
||||
("485627038", "Poustková", "Jiřina"),
|
||||
("506109148", "Holubcová", "Svatava"),
|
||||
("6008040247", "Šulc", "Jiří"),
|
||||
("6054574130", "Přibová", "Darina"),
|
||||
("6102694070", "Elouchefoun", "Aziz"),
|
||||
("6654251978", "Svozilová", "Ivana"),
|
||||
("6808292018", "Moudrý", "Jiří"),
|
||||
("6853222079", "Milatová", "Martina"),
|
||||
("6909154934", "Novák", "Petr"),
|
||||
("7056764319", "Michlíková", "Anna"),
|
||||
("7157734210", "Moudry Molloy", "Joanne"),
|
||||
("7309300449", "Vojáček", "Aleš"),
|
||||
("7410540709", "Torres blanco", "Jose maria"),
|
||||
("7459303599", "Noháčová", "Kateřina"),
|
||||
("7651090106", "Matějková", "Jana"),
|
||||
("7803744597", "Barrell", "Peter"),
|
||||
("7855080420", "Vondřičková", "Zuzana"),
|
||||
("7908030427", "Smetana", "Libor"),
|
||||
("7957312099", "Nimeřická", "Michaela"),
|
||||
("7961794126", "Tomyshynets", "Halyna"),
|
||||
("8005291404", "Hanzl", "František"),
|
||||
("8156013041", "Maršíková", "Simona"),
|
||||
("8157544241", "Jarošová", "Zuzana"),
|
||||
("8203120299", "Otčenášek", "Vojtěch"),
|
||||
("8253215223", "Slavíková", "Kateřina"),
|
||||
("8301070558", "Kříž", "Michal"),
|
||||
("8352210438", "Bartáková", "Jana"),
|
||||
("8412175123", "Mičulka", "Jan"),
|
||||
("8454664262", "Feoktistová", "Irina"),
|
||||
("8462150147", "Říhová", "Markéta"),
|
||||
("8503120417", "Šindelář", "Tomáš"),
|
||||
("8552170517", "Slabá", "Gabriela"),
|
||||
("8558150227", "Horáková", "Lucie"),
|
||||
("8652034380", "Kopová", "Jana"),
|
||||
("8754280403", "Jindrová", "Helena"),
|
||||
("8755075153", "Babjáková", "Jana"),
|
||||
("8910584023", "Pham Van", "Duy"),
|
||||
("8953010330", "Špatná", "Markéta"),
|
||||
("8956039037", "Slavíková", "Zuzana"),
|
||||
("9002025956", "Banáš", "Martin"),
|
||||
("9010262448", "Bečica", "Marek"),
|
||||
("9811040305", "Sidej", "Natan"),
|
||||
]
|
||||
|
||||
# ── INIT ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
vzp = VZPB2BClient(ENV, str(PFX_PATH), PFX_PASSWORD, icz=ICZ, dic=DIC)
|
||||
mysql = connect_mysql()
|
||||
call_count = 0
|
||||
today = date.today()
|
||||
|
||||
# ── HELPERS ───────────────────────────────────────────────────────────────────
|
||||
|
||||
def check_stav(rc: str, check_date: date) -> str:
|
||||
global call_count
|
||||
if call_count > 0:
|
||||
time.sleep(API_DELAY)
|
||||
call_count += 1
|
||||
print(f" [{call_count}] {check_date.isoformat()} ...", end=" ", flush=True)
|
||||
xml = vzp.stav_pojisteni(rc=rc, k_datu=check_date.isoformat())
|
||||
stav = vzp.parse_stav_pojisteni(xml)["stav"]
|
||||
print(f"stav = {stav!r}")
|
||||
return stav
|
||||
|
||||
def uloz_stav(rc, prijmeni, jmeno, k_datu, stav):
|
||||
xml = vzp.stav_pojisteni(rc=rc, k_datu=k_datu.isoformat())
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("""
|
||||
INSERT INTO vzp_stav_pojisteni (rc, prijmeni, jmeno, k_datu, stav, response_xml)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE stav=VALUES(stav), response_xml=VALUES(response_xml)
|
||||
""", (rc, prijmeni, jmeno, k_datu, stav, xml))
|
||||
|
||||
def najdi_zlom(rc: str, last_ok_mysql) -> tuple:
|
||||
if last_ok_mysql:
|
||||
low = last_ok_mysql
|
||||
high = today
|
||||
print(f" MySQL last stav='1': {low} → [{low} … {high}]")
|
||||
else:
|
||||
print(" MySQL: žádný stav='1' — hledám zpětně po rocích ...")
|
||||
prev_probe = today
|
||||
low = high = None
|
||||
for n in range(1, 21):
|
||||
y = today.year - n
|
||||
try:
|
||||
probe = date(y, today.month, today.day)
|
||||
except ValueError:
|
||||
probe = date(y, today.month, today.day - 1)
|
||||
stav = check_stav(rc, probe)
|
||||
if stav == "1":
|
||||
low = probe
|
||||
high = prev_probe
|
||||
print(f" Nalezeno stav='1' k {low} → [{low} … {high}]")
|
||||
break
|
||||
prev_probe = probe
|
||||
if low is None:
|
||||
print(" NELZE: stav='1' nenalezen ani 20 let zpět.")
|
||||
return None, None
|
||||
|
||||
stav_low = check_stav(rc, low)
|
||||
stav_high = check_stav(rc, high)
|
||||
|
||||
if stav_low != "1":
|
||||
print(f" NELZE: dolní mez {low} má stav='{stav_low}'.")
|
||||
return None, None
|
||||
if stav_high == "1":
|
||||
print(f" INFO: horní mez {high} má stav='1' — aktuálně pojištěn.")
|
||||
return None, None
|
||||
|
||||
print(f" Binární hledání ({(high - low).days} dní) ...")
|
||||
while (high - low).days > 1:
|
||||
mid = low + timedelta(days=(high - low).days // 2)
|
||||
stav = check_stav(rc, mid)
|
||||
if stav == "1":
|
||||
low = mid
|
||||
else:
|
||||
high = mid
|
||||
|
||||
return low, high # insured_to, uninsured_from
|
||||
|
||||
# ── RESUME: načti již hotové ──────────────────────────────────────────────────
|
||||
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("SELECT rc FROM vzp_stav_pojisteni WHERE k_datu = %s", (K_DATU,))
|
||||
hotove = {row[0] for row in cur.fetchall()}
|
||||
|
||||
zbyvaji = [(rc, p, j) for rc, p, j in PACIENTI if rc not in hotove]
|
||||
print(f"Celkem pacientů: {len(PACIENTI)}, již hotovo: {len(hotove)}, zbývá: {len(zbyvaji)}")
|
||||
print(f"API prodleva: {API_DELAY}s | K_DATU: {K_DATU}\n")
|
||||
print("=" * 60)
|
||||
|
||||
# ── HLAVNÍ SMYČKA ─────────────────────────────────────────────────────────────
|
||||
|
||||
vysledky = []
|
||||
|
||||
for i, (rc, prijmeni, jmeno) in enumerate(zbyvaji, 1):
|
||||
print(f"\n[{i}/{len(zbyvaji)}] {prijmeni} {jmeno} (RC: {rc})")
|
||||
|
||||
# Krok 1: stav k K_DATU
|
||||
if call_count > 0:
|
||||
time.sleep(API_DELAY)
|
||||
call_count += 1
|
||||
print(f" [{call_count}] {K_DATU.isoformat()} ...", end=" ", flush=True)
|
||||
xml_hist = vzp.stav_pojisteni(rc=rc, k_datu=K_DATU.isoformat())
|
||||
stav_hist = vzp.parse_stav_pojisteni(xml_hist)["stav"]
|
||||
print(f"stav = {stav_hist!r}")
|
||||
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("""
|
||||
INSERT INTO vzp_stav_pojisteni (rc, prijmeni, jmeno, k_datu, stav, response_xml)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE stav=VALUES(stav), response_xml=VALUES(response_xml)
|
||||
""", (rc, prijmeni, jmeno, K_DATU, stav_hist, xml_hist))
|
||||
|
||||
# Krok 2: zlom (jen pokud stav != '1' a != '4')
|
||||
insured_to = uninsured_from = None
|
||||
|
||||
if stav_hist in ("1", "4"):
|
||||
print(f" → pojištěn (stav={stav_hist!r}), zlom se nehledá")
|
||||
else:
|
||||
# Zkontroluj watchlist
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("SELECT insured_to, uninsured_from FROM vzp_sledovani_pojisteni WHERE rc = %s", (rc,))
|
||||
existuje = cur.fetchone()
|
||||
|
||||
if existuje:
|
||||
insured_to, uninsured_from = existuje
|
||||
print(f" → již ve watchlistu: insured_to={insured_to}, uninsured_from={uninsured_from}")
|
||||
else:
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT MAX(k_datu) FROM vzp_stav_pojisteni WHERE rc = %s AND stav = '1'",
|
||||
(rc,)
|
||||
)
|
||||
r = cur.fetchone()
|
||||
last_ok = r[0] if r and r[0] else None
|
||||
|
||||
insured_to, uninsured_from = najdi_zlom(rc, last_ok)
|
||||
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("""
|
||||
INSERT INTO vzp_sledovani_pojisteni
|
||||
(rc, prijmeni, jmeno, insured_to, uninsured_from,
|
||||
aktualni_stav, prvni_detekce, posledni_kontrola)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
insured_to=VALUES(insured_to),
|
||||
uninsured_from=VALUES(uninsured_from),
|
||||
aktualni_stav=VALUES(aktualni_stav),
|
||||
posledni_kontrola=VALUES(posledni_kontrola)
|
||||
""", (rc, prijmeni, jmeno, insured_to, uninsured_from,
|
||||
stav_hist, today, today))
|
||||
|
||||
vysledky.append({
|
||||
"rc": rc, "prijmeni": prijmeni, "jmeno": jmeno,
|
||||
"stav_20250101": stav_hist,
|
||||
"insured_to": insured_to,
|
||||
"uninsured_from": uninsured_from,
|
||||
})
|
||||
|
||||
# ── SOUHRN ────────────────────────────────────────────────────────────────────
|
||||
|
||||
mysql.close()
|
||||
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f" SOUHRN — {len(vysledky)} zpracovaných pacientů")
|
||||
print(f"{'=' * 60}")
|
||||
print(f" {'Příjmení':<20} {'Jméno':<14} {'Stav':>5} {'Pojištěn do':<13} {'Nepoj. od'}")
|
||||
print(f" {'-'*58}")
|
||||
for v in vysledky:
|
||||
ins = str(v["insured_to"]) if v["insured_to"] else "-"
|
||||
uni = str(v["uninsured_from"]) if v["uninsured_from"] else "-"
|
||||
print(f" {v['prijmeni']:<20} {v['jmeno']:<14} {v['stav_20250101']:>5} {ins:<13} {uni}")
|
||||
|
||||
print(f"\nCelkem VZP dotazů: {call_count}")
|
||||
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
zkontroluj_rc_jednorazove.py
|
||||
=============================
|
||||
Jednorázový skript pro libovolné RC:
|
||||
1. Dotáže VZP na stav pojištění k zadanému K_DATU.
|
||||
2. Uloží do vzp_stav_pojisteni.
|
||||
3. Pokud stav != '1' a != '4', spustí binární hledání zlomu
|
||||
a uloží do vzp_sledovani_pojisteni.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from datetime import date, timedelta
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from Knihovny.mysql_db import connect_mysql
|
||||
from Knihovny.vzpb2b_client import VZPB2BClient
|
||||
|
||||
# ── KONFIGURACE ───────────────────────────────────────────────────────────────
|
||||
|
||||
RC = "430127082"
|
||||
PRIJMENI = "Anderle"
|
||||
JMENO = "Václav"
|
||||
K_DATU = date(2025, 1, 1) # datum pro první dotaz
|
||||
|
||||
PFX_PATH = Path(__file__).resolve().parent.parent / "Certificates" / "picka.pfx"
|
||||
PFX_PASSWORD = "Vlado7309208104+"
|
||||
ICZ = "00000000"
|
||||
DIC = "00000000"
|
||||
ENV = "prod"
|
||||
|
||||
API_DELAY = 2
|
||||
|
||||
# ── INIT ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
vzp = VZPB2BClient(ENV, str(PFX_PATH), PFX_PASSWORD, icz=ICZ, dic=DIC)
|
||||
mysql = connect_mysql()
|
||||
call_count = 0
|
||||
today = date.today()
|
||||
|
||||
def check_stav(rc: str, check_date: date) -> str:
|
||||
global call_count
|
||||
if call_count > 0:
|
||||
time.sleep(API_DELAY)
|
||||
call_count += 1
|
||||
print(f" [{call_count}] VZP dotaz k {check_date.isoformat()} ...", end=" ", flush=True)
|
||||
xml = vzp.stav_pojisteni(rc=rc, k_datu=check_date.isoformat())
|
||||
stav = vzp.parse_stav_pojisteni(xml)["stav"]
|
||||
print(f"stav = {stav!r}")
|
||||
return stav
|
||||
|
||||
def uloz_stav(rc, prijmeni, jmeno, k_datu, stav, xml):
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("""
|
||||
INSERT INTO vzp_stav_pojisteni
|
||||
(rc, prijmeni, jmeno, k_datu, stav, response_xml)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE stav=VALUES(stav), response_xml=VALUES(response_xml)
|
||||
""", (rc, prijmeni, jmeno, k_datu, stav, xml))
|
||||
|
||||
def najdi_zlom(rc, last_ok_mysql):
|
||||
if last_ok_mysql:
|
||||
low = last_ok_mysql
|
||||
high = today
|
||||
print(f" MySQL last stav='1': {low} -> [{low} ... {high}]")
|
||||
else:
|
||||
print(" MySQL: žádný stav='1' — hledám zpětně po rocích ...")
|
||||
prev_probe = today
|
||||
low = high = None
|
||||
for n in range(1, 21):
|
||||
y = today.year - n
|
||||
try:
|
||||
probe = date(y, today.month, today.day)
|
||||
except ValueError:
|
||||
probe = date(y, today.month, today.day - 1)
|
||||
stav = check_stav(rc, probe)
|
||||
if stav == "1":
|
||||
low = probe
|
||||
high = prev_probe
|
||||
print(f" Nalezeno stav='1' k {low} -> [{low} ... {high}]")
|
||||
break
|
||||
prev_probe = probe
|
||||
if low is None:
|
||||
print(" NELZE: stav='1' nenalezen ani 20 let zpět.")
|
||||
return None, None
|
||||
|
||||
stav_low = check_stav(rc, low)
|
||||
stav_high = check_stav(rc, high)
|
||||
|
||||
if stav_low != "1":
|
||||
print(f" NELZE: dolní mez {low} má stav='{stav_low}'.")
|
||||
return None, None
|
||||
if stav_high == "1":
|
||||
print(f" INFO: horní mez {high} má stav='1' — pacient je aktuálně pojištěn, žádný zlom.")
|
||||
return None, None
|
||||
|
||||
print(f" Binární hledání v rozsahu {(high - low).days} dní ...")
|
||||
while (high - low).days > 1:
|
||||
mid = low + timedelta(days=(high - low).days // 2)
|
||||
stav = check_stav(rc, mid)
|
||||
if stav == "1":
|
||||
low = mid
|
||||
else:
|
||||
high = mid
|
||||
|
||||
return low, high # insured_to, uninsured_from
|
||||
|
||||
# ── KROK 1: Dotaz k zadanému datu ─────────────────────────────────────────────
|
||||
|
||||
print(f"\n{PRIJMENI} {JMENO} (RC: {RC})")
|
||||
print(f"── Krok 1: stav pojištění k {K_DATU} ─────────────────────────────────")
|
||||
|
||||
xml_hist = vzp.stav_pojisteni(rc=RC, k_datu=K_DATU.isoformat())
|
||||
stav_hist = vzp.parse_stav_pojisteni(xml_hist)["stav"]
|
||||
call_count += 1
|
||||
print(f" stav k {K_DATU}: {stav_hist!r}")
|
||||
|
||||
uloz_stav(RC, PRIJMENI, JMENO, K_DATU, stav_hist, xml_hist)
|
||||
print(f" Uloženo do vzp_stav_pojisteni (k_datu={K_DATU})")
|
||||
|
||||
# ── KROK 2: Pokud není pojištěn, najdi zlom ───────────────────────────────────
|
||||
|
||||
if stav_hist in ("1", "4"):
|
||||
print(f"\nStav '{stav_hist}' = pojištěn (nebo cizinec), zlom se nehledá.")
|
||||
else:
|
||||
print(f"\nStav '{stav_hist}' = nepojištěn/nenalezen")
|
||||
print(f"── Krok 2: hledám zlom pojištění ─────────────────────────────────────")
|
||||
|
||||
# Zkontroluj, zda je pacient již ve watchlistu
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("SELECT insured_to, uninsured_from FROM vzp_sledovani_pojisteni WHERE rc = %s", (RC,))
|
||||
existuje = cur.fetchone()
|
||||
|
||||
if existuje:
|
||||
print(f" Pacient již ve watchlistu: insured_to={existuje[0]}, uninsured_from={existuje[1]}")
|
||||
print(f" Přeskakuji hledání zlomu.")
|
||||
else:
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT MAX(k_datu) FROM vzp_stav_pojisteni WHERE rc = %s AND stav = '1'",
|
||||
(RC,)
|
||||
)
|
||||
r = cur.fetchone()
|
||||
last_ok = r[0] if r and r[0] else None
|
||||
|
||||
insured_to, uninsured_from = najdi_zlom(RC, last_ok)
|
||||
|
||||
with mysql.cursor() as cur:
|
||||
cur.execute("""
|
||||
INSERT INTO vzp_sledovani_pojisteni
|
||||
(rc, prijmeni, jmeno, insured_to, uninsured_from,
|
||||
aktualni_stav, prvni_detekce, posledni_kontrola)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
insured_to=VALUES(insured_to),
|
||||
uninsured_from=VALUES(uninsured_from),
|
||||
aktualni_stav=VALUES(aktualni_stav),
|
||||
posledni_kontrola=VALUES(posledni_kontrola)
|
||||
""", (RC, PRIJMENI, JMENO, insured_to, uninsured_from,
|
||||
stav_hist, today, today))
|
||||
|
||||
print(f"\n{'=' * 50}")
|
||||
print(f" VÝSLEDEK — {PRIJMENI} {JMENO} (RC: {RC})")
|
||||
print(f"{'=' * 50}")
|
||||
print(f" Stav k {K_DATU} : {stav_hist!r}")
|
||||
print(f" Poslední den pojištěn : {insured_to or 'nezjištěno'}")
|
||||
print(f" První den bez pojištění : {uninsured_from or 'nezjištěno'}")
|
||||
print(f" Celkem VZP dotazů : {call_count}")
|
||||
print(f"{'=' * 50}\n")
|
||||
|
||||
mysql.close()
|
||||
print(f"Hotovo. Celkem VZP dotazů: {call_count}")
|
||||
Reference in New Issue
Block a user