notebook vb
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
"""
|
||||
003_aktivni_PN_seznam.py
|
||||
========================
|
||||
Vypíše seznam pacientů s aktivní pracovní neschopností (PN) k dnešnímu datu.
|
||||
|
||||
SQL logika převzata přímo z Medicusu (report "Přehled práce neschopných pacientů"):
|
||||
- ZACNES <= dnes
|
||||
- (KONNES >= dnes) OR (KONNES IS NULL)
|
||||
- PRACNE = 'A'
|
||||
- STORNO <> 'T'
|
||||
|
||||
Spouštění: tlačítkem z Medicusu nebo přímo pythonu.
|
||||
"""
|
||||
import sys, os, traceback
|
||||
|
||||
_LOG = r"C:\Users\vlado\PycharmProjects\Medicus\PNWithClaude\003_error.log"
|
||||
|
||||
def _log_exception(exc_type, exc_value, exc_tb):
|
||||
with open(_LOG, "w", encoding="utf-8") as f:
|
||||
traceback.print_exception(exc_type, exc_value, exc_tb, file=f)
|
||||
sys.excepthook = _log_exception
|
||||
|
||||
import fdb
|
||||
import datetime
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
# ── Připojení ─────────────────────────────────────────────────────────────────
|
||||
DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
||||
USER = 'SYSDBA'
|
||||
PASSWORD = 'masterkey'
|
||||
CHARSET = 'win1250'
|
||||
|
||||
# ── SQL ───────────────────────────────────────────────────────────────────────
|
||||
SQL = """
|
||||
SELECT
|
||||
kar.PRIJMENI,
|
||||
kar.JMENO,
|
||||
kar.RODCIS,
|
||||
nes.ZACNES,
|
||||
nes.KONNES,
|
||||
nes.DIAGNO,
|
||||
COALESCE(nes.ECN, nes.CISNES) AS CISNES
|
||||
FROM NES nes
|
||||
JOIN KAR kar ON kar.IDPAC = nes.IDPAC
|
||||
WHERE
|
||||
nes.ZACNES <= ?
|
||||
AND (nes.KONNES >= ? OR nes.KONNES IS NULL)
|
||||
AND nes.PRACNE = 'A'
|
||||
AND nes.STORNO <> 'T'
|
||||
ORDER BY kar.PRIJMENI, kar.JMENO
|
||||
"""
|
||||
|
||||
|
||||
def nacti_data():
|
||||
dnes = datetime.date.today()
|
||||
conn = fdb.connect(dsn=DSN, user=USER, password=PASSWORD, charset=CHARSET)
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute(SQL, (dnes, dnes))
|
||||
rows = cur.fetchall()
|
||||
return dnes, rows
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def delka_PN(zacnes, konnes, dnes):
|
||||
"""Počet dní PN (od začátku do dnes nebo do konce)."""
|
||||
do = konnes if konnes else dnes
|
||||
return (do - zacnes).days + 1
|
||||
|
||||
|
||||
def zobraz_okno(dnes, rows):
|
||||
root = tk.Tk()
|
||||
root.title(f"Aktivní pracovní neschopnost – {dnes.strftime('%d.%m.%Y')}")
|
||||
w, h = 900, 550
|
||||
root.update_idletasks()
|
||||
sw = root.winfo_screenwidth()
|
||||
sh = root.winfo_screenheight()
|
||||
x = (sw - w) // 2
|
||||
y = (sh - h) // 2
|
||||
root.geometry(f"{w}x{h}+{x}+{y}")
|
||||
|
||||
# ── Záhlaví ───────────────────────────────────────────────────────────────
|
||||
hlavicka = tk.Frame(root, bg="#2c5f8a", pady=8)
|
||||
hlavicka.pack(fill=tk.X)
|
||||
tk.Label(
|
||||
hlavicka,
|
||||
text=f"Pracovní neschopnost – aktivní k {dnes.strftime('%d.%m.%Y')} ({len(rows)} pacientů)",
|
||||
font=("Segoe UI", 13, "bold"),
|
||||
fg="white", bg="#2c5f8a"
|
||||
).pack()
|
||||
|
||||
# ── Tabulka ───────────────────────────────────────────────────────────────
|
||||
cols = ("Příjmení", "Jméno", "Rodné číslo", "Začátek", "Konec", "Dní", "Diagnóza", "Č. neschopenky")
|
||||
frame = tk.Frame(root)
|
||||
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||||
|
||||
scroll_y = tk.Scrollbar(frame, orient=tk.VERTICAL)
|
||||
scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
scroll_x = tk.Scrollbar(frame, orient=tk.HORIZONTAL)
|
||||
scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
|
||||
tree = ttk.Treeview(
|
||||
frame,
|
||||
columns=cols,
|
||||
show="headings",
|
||||
yscrollcommand=scroll_y.set,
|
||||
xscrollcommand=scroll_x.set
|
||||
)
|
||||
scroll_y.config(command=tree.yview)
|
||||
scroll_x.config(command=tree.xview)
|
||||
|
||||
# Šířky sloupců
|
||||
widths = [120, 100, 110, 85, 85, 50, 80, 150]
|
||||
for col, w in zip(cols, widths):
|
||||
tree.column(col, width=w, anchor=tk.W)
|
||||
|
||||
# ── Řazení kliknutím na záhlaví ───────────────────────────────────────────
|
||||
_sort_state = {} # col -> ascending True/False
|
||||
|
||||
def sort_by(col):
|
||||
ascending = not _sort_state.get(col, False)
|
||||
_sort_state[col] = ascending
|
||||
# Index sloupce pro čtení hodnoty
|
||||
col_idx = cols.index(col)
|
||||
data = [(tree.set(k, col), k) for k in tree.get_children("")]
|
||||
# Číselné řazení pro "Dní"
|
||||
if col == "Dní":
|
||||
data.sort(key=lambda t: int(t[0]) if t[0].isdigit() else 0, reverse=not ascending)
|
||||
else:
|
||||
data.sort(key=lambda t: t[0].lower(), reverse=not ascending)
|
||||
for idx, (_, k) in enumerate(data):
|
||||
tree.move(k, "", idx)
|
||||
# Šipka v záhlaví
|
||||
for c in cols:
|
||||
arrow = (" ▲" if ascending else " ▼") if c == col else ""
|
||||
tree.heading(c, text=c + arrow, command=lambda c=c: sort_by(c))
|
||||
# Obarvi znovu střídavě
|
||||
for idx, (_, k) in enumerate(data):
|
||||
current_tags = list(tree.item(k, "tags"))
|
||||
dlouha = "dlouha" in current_tags
|
||||
if dlouha:
|
||||
tree.item(k, tags=("dlouha",))
|
||||
else:
|
||||
tree.item(k, tags=("even" if idx % 2 == 0 else "odd",))
|
||||
|
||||
for col in cols:
|
||||
tree.heading(col, text=col, command=lambda c=col: sort_by(c))
|
||||
|
||||
# Střídavé barvy řádků
|
||||
tree.tag_configure("even", background="#f0f4f8")
|
||||
tree.tag_configure("odd", background="white")
|
||||
tree.tag_configure("dlouha", foreground="#c0392b") # červeně > 90 dní
|
||||
|
||||
for i, row in enumerate(rows):
|
||||
prijmeni, jmeno, rodcis, zacnes, konnes, diagno, cisnes = row
|
||||
dni = delka_PN(zacnes, konnes, dnes)
|
||||
konec_str = konnes.strftime("%d.%m.%Y") if konnes else "trvá"
|
||||
diagno_str = (diagno or "").strip()
|
||||
cisnes_str = (cisnes or "").strip()
|
||||
|
||||
tag = "dlouha" if dni > 90 else ("even" if i % 2 == 0 else "odd")
|
||||
tree.insert("", tk.END, values=(
|
||||
prijmeni,
|
||||
jmeno,
|
||||
rodcis,
|
||||
zacnes.strftime("%d.%m.%Y"),
|
||||
konec_str,
|
||||
dni,
|
||||
diagno_str,
|
||||
cisnes_str,
|
||||
), tags=(tag,))
|
||||
|
||||
tree.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# ── Výchozí řazení: Dní vzestupně ─────────────────────────────────────────
|
||||
sort_by("Dní")
|
||||
|
||||
# ── Legenda + zavřít ──────────────────────────────────────────────────────
|
||||
spodek = tk.Frame(root, pady=6)
|
||||
spodek.pack(fill=tk.X)
|
||||
tk.Label(
|
||||
spodek,
|
||||
text="Červeně = PN delší než 90 dní",
|
||||
font=("Segoe UI", 9),
|
||||
fg="#c0392b"
|
||||
).pack(side=tk.LEFT, padx=15)
|
||||
tk.Button(
|
||||
spodek,
|
||||
text="Zavřít",
|
||||
command=root.destroy,
|
||||
width=12,
|
||||
font=("Segoe UI", 10)
|
||||
).pack(side=tk.RIGHT, padx=15)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
|
||||
# ── Hlavní tok ────────────────────────────────────────────────────────────────
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
dnes, rows = nacti_data()
|
||||
zobraz_okno(dnes, rows)
|
||||
except Exception:
|
||||
with open(_LOG, "w", encoding="utf-8") as f:
|
||||
traceback.print_exc(file=f)
|
||||
raise
|
||||
Reference in New Issue
Block a user