292 lines
8.4 KiB
Markdown
292 lines
8.4 KiB
Markdown
# PNWithClaude – Dokumentace projektu
|
||
|
||
> **Účel:** Python skripty spouštěné tlačítkem z Medicusu, které rozšiřují možnosti
|
||
> vestavěných reportů. Vznikly díky SQL loggeru/debuggeru v Medicusu, který odhalil
|
||
> strukturu databáze.
|
||
|
||
---
|
||
|
||
## Prostředí
|
||
|
||
| Položka | Hodnota |
|
||
|---|---|
|
||
| Python | 3.12.9 (64-bit) |
|
||
| Python exe | `C:\Users\vlado\PycharmProjects\Medicus\.venv\Scripts\python.exe` |
|
||
| Pythonw exe | `C:\Users\vlado\PycharmProjects\Medicus\.venv\Scripts\pythonw.exe` |
|
||
| Projekt | `C:\Users\vlado\PycharmProjects\Medicus\` |
|
||
| Skripty | `C:\Users\vlado\PycharmProjects\Medicus\PNWithClaude\` |
|
||
| Databáze | Firebird – `localhost:c:\medicus 3\data\medicus.fdb` |
|
||
|
||
### Klíčové Python balíčky
|
||
- `fdb` – Firebird databázový driver
|
||
- `tkinter` – GUI (součást Pythonu, není třeba instalovat)
|
||
|
||
---
|
||
|
||
## Připojení k databázi
|
||
|
||
```python
|
||
import fdb
|
||
|
||
conn = fdb.connect(
|
||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||
user='SYSDBA',
|
||
password='masterkey',
|
||
charset='win1250'
|
||
)
|
||
```
|
||
|
||
> ⚠️ Charset `win1250` je kritický – bez něj jsou česká písmena rozbitá.
|
||
|
||
---
|
||
|
||
## Konvence pojmenování skriptů
|
||
|
||
```
|
||
NNN_popisne_jmeno.py
|
||
```
|
||
- `NNN` = třímístné číslo (001, 002, 003, ...)
|
||
- Příklad: `003_aktivni_PN_seznam.py`
|
||
|
||
---
|
||
|
||
## Jak nastavit tlačítko v Medicusu
|
||
|
||
Medicus → **Konfigurace → Externí programy** (nebo Nástroje → Nastavení)
|
||
|
||
### Pole v dialogu „Externí program"
|
||
|
||
| Pole | Hodnota |
|
||
|---|---|
|
||
| **Příkazový řádek** | `"C:\Users\vlado\PycharmProjects\Medicus\.venv\Scripts\pythonw.exe" "C:\Users\vlado\PycharmProjects\Medicus\PNWithClaude\NNN_skript.py"` |
|
||
| **Program** | `C:\Users\vlado\PycharmProjects\Medicus\.venv\Scripts\pythonw.exe` |
|
||
| **Spustit v** | *(nechat prázdné)* |
|
||
| **Popis** | Název tlačítka v Medicusu |
|
||
| **Pacient** | ☐ nezaškrtávat (pokud skript nepotřebuje aktuálního pacienta) |
|
||
|
||
> ⚠️ **`pythonw.exe`** místo `python.exe` = žádné černé konzolové okno!
|
||
>
|
||
> ⚠️ **„Spustit v" nechat prázdné** – Medicus hlásí chybu pokud složka
|
||
> „neexistuje" (i když existuje), ale hlavně to nepotřebujeme,
|
||
> protože používáme absolutní cesty všude.
|
||
|
||
### Jak přidat tlačítko na lištu
|
||
Po uložení externího programu → pravým tlačítkem na lištu → přizpůsobit →
|
||
najít nový program → přetáhnout na lištu.
|
||
|
||
### Předávání dat z Medicusu skriptu
|
||
Medicus umí předat proměnné přes příkazový řádek, např.:
|
||
```
|
||
"pythonw.exe" "skript.py" "%RODCISN%" "%JMENO%" "%PRIJMENI%"
|
||
```
|
||
Dostupné proměnné (ukázka ze stávající konfigurace laboratoře):
|
||
- `%JMENO%` – jméno pacienta
|
||
- `%PRIJMENI%` – příjmení
|
||
- `%RODCISN%` – rodné číslo (bez lomítka)
|
||
- `%POJ%` – pojišťovna
|
||
- `%DGN%` – diagnóza
|
||
|
||
V Pythonu pak čteš: `sys.argv[1]`, `sys.argv[2]`, atd.
|
||
|
||
---
|
||
|
||
## Jak zjistit SQL dotazy Medicusu – SQL Logger
|
||
|
||
1. Medicus → **Nástroje → SQL Monitor** (nebo podobně v menu)
|
||
2. Zapnout logging
|
||
3. Provést akci v Medicusu (otevřít záložku, spustit report)
|
||
4. Zkopírovat SQL z logu
|
||
|
||
Log se ukládá do: `C:\Medicus 3\Debug\Monitor_DDMMYY_HHMMSS.log`
|
||
|
||
> 💡 **Zlatý důl!** SQL logger odhalí přesnou strukturu tabulek a podmínky
|
||
> filtrování, které Medicus interně používá.
|
||
|
||
---
|
||
|
||
## Struktura databáze – klíčové tabulky
|
||
|
||
### Pacienti
|
||
| Tabulka | Popis |
|
||
|---|---|
|
||
| `KAR` | Kartotéka pacientů – `IDPAC`, `PRIJMENI`, `JMENO`, `RODCIS` |
|
||
|
||
### Pracovní neschopnost (PN)
|
||
| Tabulka | Popis |
|
||
|---|---|
|
||
| `NES` | **Hlavní tabulka neschopenek** |
|
||
| `HPN` | Elektronická podání na ČSSZ (eNeschopenka) – komunikační vrstva, 5693 záznamů |
|
||
| `HPN_NOTIFIKACE` | Notifikace z ČSSZ |
|
||
| `HPN_NOTIFIKACE_DETAIL` | Detail notifikací, stavy podání (`STAV_PODANI`) |
|
||
| `HPN_PODANI` | Podání na ČSSZ |
|
||
| `HOSPNES` | Hospitalizační neschopenky |
|
||
|
||
### Klíčové sloupce tabulky `NES`
|
||
| Sloupec | Popis |
|
||
|---|---|
|
||
| `IDPAC` | ID pacienta (JOIN s KAR) |
|
||
| `ZACNES` | Začátek PN (DATE) |
|
||
| `KONNES` | Konec PN (DATE) – NULL = stále trvá |
|
||
| `DIAGNO` | Diagnóza (MKN-10 kód) |
|
||
| `CISNES` | Číslo neschopenky (starý formát) |
|
||
| `ECN` | eČíslo neschopenky (nový elektronický formát) |
|
||
| `PRACNE` | Pracovní neschopnost = `'A'` |
|
||
| `STORNO` | Storno záznamu = `'T'` (True) |
|
||
| `STATDPNKOD` | Stav DPN kód |
|
||
| `VERZE_DPN` | Verze DPN |
|
||
|
||
---
|
||
|
||
## SQL – aktivní PN k dnešnímu datu
|
||
|
||
```sql
|
||
SELECT
|
||
kar.PRIJMENI,
|
||
kar.JMENO,
|
||
kar.RODCIS,
|
||
nes.ZACNES,
|
||
nes.KONNES,
|
||
nes.DIAGNO,
|
||
COALESCE(nes.ECN, nes.CISNES) AS CISNES -- preferuj eČíslo, fallback na staré
|
||
FROM NES nes
|
||
JOIN KAR kar ON kar.IDPAC = nes.IDPAC
|
||
WHERE
|
||
nes.ZACNES <= CAST('TODAY' AS DATE)
|
||
AND (nes.KONNES >= CAST('TODAY' AS DATE) OR nes.KONNES IS NULL)
|
||
AND nes.PRACNE = 'A'
|
||
AND nes.STORNO <> 'T'
|
||
ORDER BY kar.PRIJMENI, kar.JMENO
|
||
```
|
||
|
||
> 💡 `COALESCE(nes.ECN, nes.CISNES)` – starší neschopenky mají jen `CISNES`,
|
||
> novější elektronické mají `ECN`. Takhle dostaneme vždy správné číslo.
|
||
|
||
---
|
||
|
||
## Šablona nového skriptu
|
||
|
||
```python
|
||
"""
|
||
NNN_nazev_skriptu.py
|
||
====================
|
||
Popis co skript dělá.
|
||
"""
|
||
import sys, os, traceback
|
||
|
||
_LOG = r"C:\Users\vlado\PycharmProjects\Medicus\PNWithClaude\NNN_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
|
||
|
||
DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
||
USER = 'SYSDBA'
|
||
PASSWORD = 'masterkey'
|
||
CHARSET = 'win1250'
|
||
|
||
SQL = """
|
||
SELECT ...
|
||
FROM ...
|
||
WHERE ...
|
||
"""
|
||
|
||
def nacti_data():
|
||
conn = fdb.connect(dsn=DSN, user=USER, password=PASSWORD, charset=CHARSET)
|
||
try:
|
||
cur = conn.cursor()
|
||
cur.execute(SQL)
|
||
return cur.fetchall()
|
||
finally:
|
||
conn.close()
|
||
|
||
def zobraz_okno(rows):
|
||
root = tk.Tk()
|
||
root.title("Název okna")
|
||
# Centrování na střed monitoru
|
||
w, h = 900, 550
|
||
root.update_idletasks()
|
||
sw, sh = root.winfo_screenwidth(), root.winfo_screenheight()
|
||
root.geometry(f"{w}x{h}+{(sw-w)//2}+{(sh-h)//2}")
|
||
# ... GUI kód ...
|
||
root.mainloop()
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
rows = nacti_data()
|
||
zobraz_okno(rows)
|
||
except Exception:
|
||
with open(_LOG, "w", encoding="utf-8") as f:
|
||
traceback.print_exc(file=f)
|
||
raise
|
||
```
|
||
|
||
---
|
||
|
||
## Řazení v ttk.Treeview – vzorový kód
|
||
|
||
```python
|
||
_sort_state = {} # uchovává směr řazení pro každý sloupec
|
||
|
||
def sort_by(col):
|
||
ascending = not _sort_state.get(col, False)
|
||
_sort_state[col] = ascending
|
||
data = [(tree.set(k, col), k) for k in tree.get_children("")]
|
||
if col == "Dní": # číselné sloupce
|
||
data.sort(key=lambda t: int(t[0]) if t[0].isdigit() else 0, reverse=not ascending)
|
||
else: # textové sloupce
|
||
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í aktivního sloupce
|
||
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))
|
||
|
||
# Připoj řazení na záhlaví
|
||
for col in cols:
|
||
tree.heading(col, text=col, command=lambda c=col: sort_by(c))
|
||
|
||
# Výchozí řazení při spuštění
|
||
sort_by("Dní")
|
||
```
|
||
|
||
---
|
||
|
||
## Ladění problémů
|
||
|
||
### Skript nefunguje z Medicusu, ale z PyCharmu ano
|
||
1. Přepnout dočasně na `python.exe` (ne `pythonw.exe`) – uvidíš konzoli
|
||
2. Zkontrolovat `NNN_error.log` v adresáři skriptů
|
||
3. Nejčastější příčiny:
|
||
- `__file__` je prázdný → používej **absolutní cesty** pro log soubory
|
||
- Chybí `fbclient.dll` v PATH → testuj test skriptem
|
||
- Pole „Spustit v" v Medicusu → **nechat prázdné**
|
||
|
||
### Test skript pro ověření prostředí
|
||
Viz `test_spusteni.py` – testuje Python, fdb import, tkinter a DB spojení.
|
||
Výstup: `Python: OK`, `fdb: OK`, `tkinter: OK`, `DB spojeni: OK`
|
||
|
||
### Černé konzolové okno
|
||
Použít `pythonw.exe` místo `python.exe` v konfiguraci Medicusu.
|
||
|
||
---
|
||
|
||
## Seznam skriptů
|
||
|
||
| Číslo | Soubor | Popis |
|
||
|---|---|---|
|
||
| 001 | `001_pruzkum_PN_tabulek.py` | Průzkum struktury DB – tabulky a sloupce s PN |
|
||
| 003 | `003_aktivni_PN_seznam.py` | **Aktivní PN k dnešnímu datu** – tlačítko na liště |
|
||
|
||
> Číslo 002 přeskočeno (bylo pracovní/testovací stadium).
|
||
|
||
---
|
||
|
||
*Projekt vznikl: březen 2026 | Medicus 3 Komfort | Firebird DB | Python 3.12*
|