notebookvb
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from datetime import date
|
||||
import customtkinter as ctk
|
||||
from tkinter import messagebox
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from Knihovny.vzpb2b_client import VZPB2BClient
|
||||
from Knihovny.EmailMessagingGraph import send_mail
|
||||
|
||||
EMAIL_CHYBY = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
def _zpracuj_chybu(exc: BaseException):
|
||||
"""Zobrazí chybový dialog a pošle email. Nikdy nevyhodí výjimku."""
|
||||
detail = traceback.format_exc()
|
||||
try:
|
||||
root = ctk.CTk()
|
||||
root.withdraw()
|
||||
messagebox.showerror("Chyba — KdoJeLekarApp",
|
||||
f"Nastala chyba:\n{exc}\n\nByla odeslána na email.")
|
||||
root.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
send_mail(
|
||||
to=EMAIL_CHYBY,
|
||||
subject=f"KdoJeLekarApp — chyba ({date.today().isoformat()})",
|
||||
body=(f"Pacient: {PRIJMENI} {JMENO} / RC: {RODCIS}\n\n{detail}"),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ── KONFIGURACE ───────────────────────────────────────────────────────────────
|
||||
|
||||
PFX_PATH = PROJECT_ROOT / "Insurance" / "Certificates" / "picka.pfx"
|
||||
PFX_PASS = "Vlado7309208104+"
|
||||
|
||||
ODBORNOSTI_NAZVY = {
|
||||
"001": "Praktický lékař",
|
||||
"002": "Gynekolog",
|
||||
"014": "Stomatolog",
|
||||
}
|
||||
|
||||
# Default hodnoty (přepíší argumenty z Medicusu)
|
||||
JMENO = "Michaela"
|
||||
PRIJMENI = "Buzalková"
|
||||
RODCIS = "7155111821"
|
||||
|
||||
# ── ARGUMENTY Z MEDICUSU ─────────────────────────────────────────────────────
|
||||
|
||||
if len(sys.argv) >= 4:
|
||||
JMENO = sys.argv[1]
|
||||
PRIJMENI = sys.argv[2]
|
||||
RODCIS = sys.argv[3]
|
||||
elif len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"):
|
||||
print("Usage: KdoJeLekarApp.py JMENO PRIJMENI RODCIS")
|
||||
sys.exit(0)
|
||||
|
||||
# ── VZP DOTAZ ────────────────────────────────────────────────────────────────
|
||||
|
||||
def zjisti_lekare(rodcis: str) -> list[dict]:
|
||||
vzp = VZPB2BClient("prod", str(PFX_PATH), PFX_PASS)
|
||||
xml = vzp.registrace_lekare(rc=rodcis, k_datu=date.today().isoformat())
|
||||
return vzp.parse_registrace_lekare(xml)
|
||||
|
||||
# ── GUI ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
class KdoJeLekarApp(ctk.CTk):
|
||||
def __init__(self, zaznamy: list[dict]):
|
||||
super().__init__()
|
||||
self.title("Registrující lékař — VZP B2B")
|
||||
self.geometry("560x560")
|
||||
self.minsize(480, 380)
|
||||
self.resizable(True, True)
|
||||
|
||||
ctk.set_appearance_mode("light")
|
||||
ctk.set_default_color_theme("blue")
|
||||
|
||||
outer = ctk.CTkFrame(self, corner_radius=10)
|
||||
outer.pack(expand=True, fill="both", padx=20, pady=20)
|
||||
outer.columnconfigure(0, weight=1)
|
||||
|
||||
ctk.CTkLabel(outer, text="Registrující lékaři",
|
||||
font=("Arial", 20, "bold")).grid(row=0, column=0, pady=(10, 8))
|
||||
|
||||
# Pacient
|
||||
poj = zaznamy[0].get("poj_zkratka", "") if zaznamy else ""
|
||||
pac = ctk.CTkFrame(outer, corner_radius=8)
|
||||
pac.grid(row=1, column=0, sticky="ew", padx=10, pady=(0, 8))
|
||||
ctk.CTkFrame(pac, height=6, fg_color="transparent").pack()
|
||||
for label, value in [
|
||||
("Příjmení:", PRIJMENI),
|
||||
("Jméno:", JMENO),
|
||||
("Rodné číslo:", RODCIS),
|
||||
("Pojišťovna:", poj),
|
||||
]:
|
||||
row = ctk.CTkFrame(pac, fg_color="transparent")
|
||||
row.pack(fill="x", padx=12, pady=0)
|
||||
ctk.CTkLabel(row, text=label, font=("Arial", 12, "bold"),
|
||||
width=100, anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkLabel(row, text=value, font=("Arial", 12),
|
||||
anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkFrame(pac, height=4, fg_color="transparent").pack()
|
||||
|
||||
# Karty lékařů
|
||||
cards = ctk.CTkFrame(outer, corner_radius=0, fg_color="transparent")
|
||||
cards.grid(row=2, column=0, sticky="ew", padx=10)
|
||||
|
||||
if not zaznamy:
|
||||
ctk.CTkLabel(cards, text="VZP neeviduje žádného registrujícího lékaře.",
|
||||
font=("Arial", 13), text_color="#c0392b").pack(pady=20)
|
||||
else:
|
||||
for z in zaznamy:
|
||||
self._render_zaznam(cards, z)
|
||||
|
||||
ctk.CTkLabel(outer,
|
||||
text=f"Dotaz k datu: {date.today().isoformat()} | © Ordinace MUDr. Buzalková",
|
||||
font=("Arial", 10), text_color="#888").grid(row=3, column=0, pady=(4, 6))
|
||||
|
||||
self._autosize()
|
||||
|
||||
def _render_zaznam(self, parent, z: dict):
|
||||
kod = z.get("kod_odbornosti", "")
|
||||
nazev_odb = ODBORNOSTI_NAZVY.get(kod, f"Odbornost {kod}")
|
||||
lekar = z.get("nazev_zzz") or "—"
|
||||
pracoviste = z.get("nazev_lekare") or "—"
|
||||
od = z.get("datum_zahajeni") or "?"
|
||||
do = z.get("datum_ukonceni") or "?"
|
||||
|
||||
card = ctk.CTkFrame(parent, corner_radius=8, fg_color="#eaf4fb")
|
||||
card.pack(fill="x", pady=4)
|
||||
|
||||
ctk.CTkLabel(card, text=f" {nazev_odb} ({kod})",
|
||||
font=("Arial", 13, "bold"), text_color="#1a5276").pack(anchor="w", padx=10, pady=(6, 1))
|
||||
|
||||
for label, value in [
|
||||
("Lékař:", lekar),
|
||||
("Pracoviště:", pracoviste),
|
||||
("ICZ / ICP:", f"{z.get('ICZ') or '—'} / {z.get('ICP') or '—'}"),
|
||||
("Registrace:", z.get("datum_registrace") or "?"),
|
||||
("Platí od:", od),
|
||||
("Platí do:", "bez omezení" if do == "3000-01-01" else do),
|
||||
]:
|
||||
row = ctk.CTkFrame(card, fg_color="transparent")
|
||||
row.pack(fill="x", padx=14, pady=0)
|
||||
ctk.CTkLabel(row, text=label, font=("Arial", 11, "bold"),
|
||||
width=90, anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkLabel(row, text=value, font=("Arial", 11),
|
||||
anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkFrame(card, height=4, fg_color="transparent").pack()
|
||||
|
||||
|
||||
def _autosize(self):
|
||||
self.update_idletasks()
|
||||
w = 560
|
||||
h = self.winfo_reqheight()
|
||||
sw, sh = self.winfo_screenwidth(), self.winfo_screenheight()
|
||||
self.geometry(f"{w}x{h}+{(sw-w)//2}+{(sh-h)//2}")
|
||||
|
||||
|
||||
# ── MAIN ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
zaznamy = zjisti_lekare(RODCIS)
|
||||
app = KdoJeLekarApp(zaznamy)
|
||||
app.mainloop()
|
||||
except Exception as exc:
|
||||
_zpracuj_chybu(exc)
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user