notebook vb
This commit is contained in:
@@ -361,3 +361,106 @@ Správný RTF formát klikacího odkazu:
|
|||||||
- Napsat `rtf_to_text()` pro extrakci čistého textu z dekurzů
|
- Napsat `rtf_to_text()` pro extrakci čistého textu z dekurzů
|
||||||
- Prozkoumat tabulky: LECH/LECD (léky?), POU (poukazy?), AMBULEKY (výkony?)
|
- Prozkoumat tabulky: LECH/LECD (léky?), POU (poukazy?), AMBULEKY (výkony?)
|
||||||
- První report – domluvit s uživatelem co chce vidět
|
- První report – domluvit s uživatelem co chce vidět
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KAR.POZNAMKA – automatické tagy (2026-04-09)
|
||||||
|
|
||||||
|
Pole `POZNAMKA` v tabulce KAR je **BLOB SUB_TYPE 1** (text blob, win1250) –
|
||||||
|
Medicus ho renderuje jako RTF stejně jako DEKURS. Lze psát i prostý text.
|
||||||
|
|
||||||
|
### Konvence automatických tagů
|
||||||
|
Automaticky zapisované informace se ukládají na **začátek** POZNAMKA ve formátu:
|
||||||
|
```
|
||||||
|
[[klic:hodnota1, hodnota2]] #zapsáno DD-MM-YYYY HH:MM#
|
||||||
|
```
|
||||||
|
- Oddělovače `[[` a `]]` se v lékařských poznámkách přirozeně nevyskytují
|
||||||
|
- Tag lze programově najít a nahradit regexem
|
||||||
|
- Ruční text lékaře/sestry pod tagem zůstává nedotčen
|
||||||
|
|
||||||
|
### Implementovaný tag: prev_prohlidka
|
||||||
|
```
|
||||||
|
[[prev_prohlidka:15-05-2024 01022, 15-04-2026]] #zapsáno 09-04-2026 14:30#
|
||||||
|
```
|
||||||
|
- `15-05-2024` = datum poslední PP
|
||||||
|
- `01022` = kód výkonu (01022 = dospělí, 01021 = starší varianta)
|
||||||
|
- `15-04-2026` = nejdřívější možný termín příští PP (23 měsíců od poslední)
|
||||||
|
- Skript: `MedicusWithClaudeTest/prev_prohlidka.py`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tabulka VZPARC – výkonové dávky pojišťovnám (zjištěno 2026-04-09)
|
||||||
|
|
||||||
|
Zachyceno přes Firebird trace log při exportu dávek z Medicusu.
|
||||||
|
|
||||||
|
### Struktura
|
||||||
|
- **1954 záznamů**, data od 2007 (s DAVKA blobem od 2013)
|
||||||
|
- Klíčové sloupce: `ID`, `ROK`, `DRUH`, `DATUMOD`, `DATUMDO`, `DAVKA` (blob), `ICP`, `ODB`, `IDICZ`
|
||||||
|
- Vazba na ICZ přes `IDICZ`
|
||||||
|
|
||||||
|
### Typy dávek (DRUH)
|
||||||
|
| DRUH | Popis |
|
||||||
|
|---|---|
|
||||||
|
| `98` | Výkonová dávka – obsahuje výkony vykázané pojišťovně (DP98 formát) |
|
||||||
|
| `05` | Doplňková dávka (DP05) |
|
||||||
|
| `80` | Registrační dávka – přihlášení/odhlášení pacientů (DP80) |
|
||||||
|
| `36` | Jiný typ |
|
||||||
|
|
||||||
|
### DAVKA blob – formát (CP852)
|
||||||
|
Stejný formát jako KDAVKA v PORTAL, dekódování identické:
|
||||||
|
```python
|
||||||
|
text = raw.encode('cp1250', errors='replace').decode('cp852', errors='replace')
|
||||||
|
```
|
||||||
|
|
||||||
|
Struktura DP98 dávky:
|
||||||
|
```
|
||||||
|
DP98... – hlavička (IČP, rok, měsíc, disk, počet případů, částka)
|
||||||
|
A ... – ambulantní případ: RC pacienta na pozici 34, délka 10
|
||||||
|
V ... – výkon: V + DDMM + YYYY + KOD(5) + ...
|
||||||
|
Z ... – ZULP
|
||||||
|
L ... – lék
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parsování RC z A řádku
|
||||||
|
```python
|
||||||
|
aktualni_rc = line[34:44].strip() # pevná pozice, délka 10
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parsování výkonu z V řádku
|
||||||
|
```python
|
||||||
|
dd = int(line[1:3])
|
||||||
|
mm = int(line[3:5])
|
||||||
|
yyyy = int(line[5:9])
|
||||||
|
kod = line[9:14].strip() # 5znakový kód výkonu
|
||||||
|
```
|
||||||
|
|
||||||
|
### Poznámka: PORTAL vs VZPARC
|
||||||
|
- **PORTAL** – starší tabulka, KDAVKA blob, data jen do 2015
|
||||||
|
- **VZPARC** – správná tabulka pro výkonové dávky, data od 2013 do dnes
|
||||||
|
- Pro hledání výkonů per pacient vždy používat **VZPARC**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Skript prev_prohlidka.py (MedicusWithClaudeTest/)
|
||||||
|
|
||||||
|
Účel: najde datum poslední preventivní prohlídky (PP) pro každého registrovaného
|
||||||
|
pacienta a zapíše/aktualizuje tag v KAR.POZNAMKA.
|
||||||
|
|
||||||
|
### Co dělá
|
||||||
|
1. Načte registrované pacienty (přesný dotaz přes REGISTR + ICP, IČP=09305001)
|
||||||
|
2. Projde všechny VZPARC DRUH=98 dávky, hledá výkony `01022` nebo `01021`
|
||||||
|
3. Pro každého pacienta zachová jen **nejnovější** datum PP
|
||||||
|
4. Zapíše/přepíše tag `[[prev_prohlidka:...]]` na začátek KAR.POZNAMKA
|
||||||
|
|
||||||
|
### Výsledek posledního spuštění (2026-04-09)
|
||||||
|
- Registrovaných pacientů: 1621
|
||||||
|
- Dávek VZPARC DRUH=98: 778
|
||||||
|
- Pacientů s nalezenou PP: 1289
|
||||||
|
- Zapsáno do KAR: 1120
|
||||||
|
- Nenalezeno (odregistrovaní nebo bez PP): 169
|
||||||
|
|
||||||
|
### Závislosti
|
||||||
|
```
|
||||||
|
pip install python-dateutil
|
||||||
|
```
|
||||||
|
(fdb již musí být nainstalováno)
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
"""
|
||||||
|
Najde datum poslední preventivní prohlídky (výkon 01022 nebo 01021)
|
||||||
|
pro každého registrovaného pacienta z VZPARC DRUH=98 (výkonové dávky pojišťovnám).
|
||||||
|
Výsledek zapíše do KAR.POZNAMKA ve formátu:
|
||||||
|
[[prev_prohlidka:YYYY-MM-DD 01022, YYYY-MM-DD]]
|
||||||
|
kde první datum je datum PP a druhé je nejdřívější možný termín příští (23 měsíců).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import fdb
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from datetime import date
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
|
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf-8', buffering=1)
|
||||||
|
|
||||||
|
KODY_PP = {'01022', '01021'}
|
||||||
|
|
||||||
|
conn = fdb.connect(
|
||||||
|
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||||
|
user='SYSDBA', password='masterkey', charset='win1250'
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# --- 1. Načti registrované pacienty (RC → IDPAC, aktuální POZNAMKA) ---
|
||||||
|
dnes = date.today().strftime('%Y-%m-%d')
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT KAR.IDPAC, KAR.RODCIS, KAR.PRIJMENI, KAR.JMENO, KAR.POZNAMKA
|
||||||
|
FROM KAR
|
||||||
|
WHERE KAR.VYRAZEN = 'N'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT r.ID FROM REGISTR r
|
||||||
|
JOIN ICP i ON r.IDICP = i.IDICP
|
||||||
|
WHERE r.IDPAC = KAR.IDPAC
|
||||||
|
AND r.DATUM <= '{dnes}'
|
||||||
|
AND (r.DATUM_ZRUSENI IS NULL OR r.DATUM_ZRUSENI >= '{dnes}')
|
||||||
|
AND r.PRIZNAK IN ('V','D','A')
|
||||||
|
AND i.ICP = '09305001'
|
||||||
|
AND i.ODB = '001'
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
pacienti = {} # RODCIS -> {'idpac', 'prijmeni', 'jmeno', 'poznamka'}
|
||||||
|
for row in cur.fetchall():
|
||||||
|
idpac, rodcis, prijmeni, jmeno, poznamka = row
|
||||||
|
if rodcis:
|
||||||
|
pacienti[rodcis.strip()] = {
|
||||||
|
'idpac': idpac,
|
||||||
|
'prijmeni': prijmeni,
|
||||||
|
'jmeno': jmeno,
|
||||||
|
'poznamka': poznamka or '',
|
||||||
|
}
|
||||||
|
print(f"Registrovaných pacientů: {len(pacienti)}")
|
||||||
|
|
||||||
|
# --- 2. Projdi všechny VZPARC DRUH=98 dávky a hledej výkony 01022/01021 ---
|
||||||
|
# Výsledek: RC -> (nejnovejsi_datum, kod)
|
||||||
|
vysledky = {} # RC -> (nejnovejsi_datum, kod)
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT DAVKA FROM VZPARC
|
||||||
|
WHERE DRUH = '98' AND DAVKA IS NOT NULL
|
||||||
|
""")
|
||||||
|
|
||||||
|
davky = cur.fetchall()
|
||||||
|
print(f"VZPARC DRUH=98 blobů celkem: {len(davky)}")
|
||||||
|
|
||||||
|
for (kdavka_raw,) in davky:
|
||||||
|
if not kdavka_raw:
|
||||||
|
continue
|
||||||
|
# Dekódování CP852
|
||||||
|
try:
|
||||||
|
text = kdavka_raw.encode('cp1250', errors='replace').decode('cp852', errors='replace')
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not text.startswith('DP98'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
aktualni_rc = None
|
||||||
|
for line in text.splitlines():
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
typ = line[0]
|
||||||
|
|
||||||
|
if typ == 'A':
|
||||||
|
# RC je na pevné pozici 34, délka 10
|
||||||
|
if len(line) >= 44:
|
||||||
|
aktualni_rc = line[34:44].strip()
|
||||||
|
else:
|
||||||
|
aktualni_rc = None
|
||||||
|
|
||||||
|
elif typ == 'V' and aktualni_rc:
|
||||||
|
# V + DDMMYYYY + KOD(5)
|
||||||
|
if len(line) < 14:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
dd = int(line[1:3])
|
||||||
|
mm = int(line[3:5])
|
||||||
|
yyyy = int(line[5:9])
|
||||||
|
kod = line[9:14].strip()
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if kod not in KODY_PP:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
datum = date(yyyy, mm, dd)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Ulož jen nejnovější datum
|
||||||
|
if aktualni_rc not in vysledky or datum > vysledky[aktualni_rc][0]:
|
||||||
|
vysledky[aktualni_rc] = (datum, kod)
|
||||||
|
|
||||||
|
print(f"Pacientů s nalezenou PP (01022/01021): {len(vysledky)}")
|
||||||
|
|
||||||
|
# --- 3. Zapiš do KAR.POZNAMKA ---
|
||||||
|
TAG_RE = re.compile(r'\[\[prev_prohlidka:[^\]]*\]\]\s*#zaps[^#]*#')
|
||||||
|
TAG_FORMAT = '[[prev_prohlidka:{pp_datum} {kod}, {pristi_datum}]] #zapsáno {zapsano}#'
|
||||||
|
|
||||||
|
zapsano = 0
|
||||||
|
preskoceno = 0
|
||||||
|
nenalezeno = 0
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
ted = datetime.now().strftime('%d-%m-%Y %H:%M')
|
||||||
|
|
||||||
|
for rc, (datum_pp, kod) in sorted(vysledky.items()):
|
||||||
|
if rc not in pacienti:
|
||||||
|
nenalezeno += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
pac = pacienti[rc]
|
||||||
|
pristi = datum_pp + relativedelta(months=23)
|
||||||
|
tag = TAG_FORMAT.format(
|
||||||
|
pp_datum=datum_pp.strftime('%d-%m-%Y'),
|
||||||
|
kod=kod,
|
||||||
|
pristi_datum=pristi.strftime('%d-%m-%Y'),
|
||||||
|
zapsano=ted,
|
||||||
|
)
|
||||||
|
|
||||||
|
stara = pac['poznamka']
|
||||||
|
# Odstraň starý tag a vlož nový na začátek
|
||||||
|
nova = TAG_RE.sub('', stara).lstrip('\n')
|
||||||
|
nova = tag + ('\n' + nova if nova else '')
|
||||||
|
|
||||||
|
cur.execute(
|
||||||
|
"UPDATE KAR SET POZNAMKA=? WHERE IDPAC=?",
|
||||||
|
(nova, pac['idpac'])
|
||||||
|
)
|
||||||
|
zapsano += 1
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
print(f"Zapsáno: {zapsano}, nenalezeno v KAR: {nenalezeno}, přeskočeno: {preskoceno}")
|
||||||
|
conn.close()
|
||||||
Reference in New Issue
Block a user