diff --git a/MedicusWithClaude/CLAUDE_NOTES.md b/MedicusWithClaude/CLAUDE_NOTES.md index 39e152b..7d86faa 100644 --- a/MedicusWithClaude/CLAUDE_NOTES.md +++ b/MedicusWithClaude/CLAUDE_NOTES.md @@ -361,3 +361,106 @@ Správný RTF formát klikacího odkazu: - Napsat `rtf_to_text()` pro extrakci čistého textu z dekurzů - Prozkoumat tabulky: LECH/LECD (léky?), POU (poukazy?), AMBULEKY (výkony?) - 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) diff --git a/MedicusWithClaudeTest/prev_prohlidka.py b/MedicusWithClaudeTest/prev_prohlidka.py new file mode 100644 index 0000000..17cfd8e --- /dev/null +++ b/MedicusWithClaudeTest/prev_prohlidka.py @@ -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()