Files
medicus/PNWithClaude/README.md
T
2026-03-25 17:32:12 +01:00

292 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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*