notebook vb
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
# 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*
|
||||
Reference in New Issue
Block a user