Files
ordinaceprojekt/Medicus/Externi/KdoJeLekar/KdoJeLekarApp.py
T
Vladimir Buzalka 67ec430fd4 notebookvb
2026-05-12 06:53:58 +02:00

189 lines
7.5 KiB
Python

#!/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
if not getattr(sys, "frozen", False):
_project_root = Path(__file__).resolve().parent.parent.parent.parent
sys.path.insert(0, str(_project_root))
from Knihovny.najdi_dropbox import get_dropbox_root
from Knihovny.vzpb2b_client import VZPB2BClient
from Knihovny.EmailMessagingGraph import send_mail
DROPBOX = Path(get_dropbox_root())
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 ───────────────────────────────────────────────────────────────
if getattr(sys, "frozen", False):
PFX_PATH = Path(sys._MEIPASS) / "picka.pfx"
else:
PFX_PATH = Path(r"U:\OrdinaceProjekt\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 = ""
PRIJMENI = ""
RODCIS = ""
# ── ARGUMENTY Z MEDICUSU ─────────────────────────────────────────────────────
if len(sys.argv) >= 4:
JMENO = sys.argv[1]
PRIJMENI = sys.argv[2]
RODCIS = sys.argv[3].replace("/", "")
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__":
if not RODCIS:
root = ctk.CTk()
root.withdraw()
messagebox.showerror("Chyba", "Nebyl předán pacient z Medicusu.\nSpusťte aplikaci z menu Medicusu nad vybraným pacientem.")
sys.exit(1)
try:
zaznamy = zjisti_lekare(RODCIS)
app = KdoJeLekarApp(zaznamy)
app.mainloop()
except Exception as exc:
_zpracuj_chybu(exc)
sys.exit(1)