notebook vb
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
- Zahájeno: 2026-03-13
|
||||
- Cíl: průzkum Firebird DB Medicus → analýzy a reporty
|
||||
- Zatím: úspěšně čteme i zapisujeme do DB, rozumíme RTF formátu
|
||||
- **2026-03-17**: Obnovena session – Claude si přečetl poznámky, připraven pokračovat
|
||||
- **2026-03-18**: Obnovena session – Claude si přečetl poznámky, připraven pokračovat. Průběžně zapisuje do tohoto souboru.
|
||||
|
||||
## Bezpečnost
|
||||
- Pracujeme na **místní kopii** – poškození DB nevadí, obnova = 5 minut
|
||||
@@ -21,6 +23,9 @@ conn = fdb.connect(
|
||||
)
|
||||
```
|
||||
- fdb verze 2.0.4, Python na PATH (prostý `python` příkaz)
|
||||
- Firebird instalace: `C:\Program Files\Firebird\Firebird_2_5_CGM\bin\`
|
||||
- Jedná se o **HQbird** (IBSurgeon enhanced Firebird) – port **3070** (ne standardní 3050)
|
||||
- fbtracemgr trace nefungoval spolehlivě – doporučeno použít **FBScanner** (stejný výrobce)
|
||||
|
||||
## O Medicusu
|
||||
- Lékařský software pro praktického lékaře
|
||||
@@ -157,6 +162,186 @@ conn.commit()
|
||||
- `insert_test.py` – testovací INSERT do DEKURS
|
||||
- `CLAUDE_NOTES.md` – tento soubor
|
||||
|
||||
## Export FILES do externích DB (zjištěno 2026-03-17 přes FBScanner)
|
||||
|
||||
### Mechanismus přesunu
|
||||
Medicus vytváří **měsíční** externí Firebird databáze ve formátu `MEDICUS_FILES_YYYYMM.fdb`.
|
||||
|
||||
**Postup exportu:**
|
||||
1. SELECT dat z FILES po 10 záznamech: `select first 10 ID, BODY, DATUM from FILES where ID > X ORDER BY ID ASC`
|
||||
2. Binární data (skeny) se zapíší do externího `.fdb` souboru
|
||||
3. V hlavní DB se BODY přepíše referenčním číslem (ID v externím souboru): `update FILES set BODY = 379 where ID = 10009`
|
||||
4. Do EXTERNI_DB se zapíše lokace: `insert into EXTERNI_DB (DBNAME, SERVER, PATH, HESLO) values ('DB202501', 'localhost/3053', 'u:\MEDICUS_FILES_202501.fdb', '<encrypted>')`
|
||||
|
||||
### Výsledek
|
||||
- Hlavní DB: FILES.BODY obsahuje jen malé číslo (referenci) místo MB blobu
|
||||
- Skenované soubory jsou fyzicky v `u:\MEDICUS_FILES_YYYYMM.fdb`
|
||||
- Medicus načítá soubory přes EXTERNI_DB tabulku (SERVER + PATH + HESLO)
|
||||
- Hesla v EXTERNI_DB jsou šifrovaná (base64 AES)
|
||||
|
||||
### FBScanner
|
||||
- Nainstalován, funguje jako proxy: Medicus → [3050] FBScanner → [3053] Firebird
|
||||
- Community Edition 2.5 – stačí pro monitoring
|
||||
- Export proveden na záloze (ne produkční DB)
|
||||
|
||||
## Přímý zápis do externí DB – dokončeno (2026-03-17)
|
||||
|
||||
### Nový soubor: `funkce_ext.py`
|
||||
Náhrada za `funkce.zapis_file()`. Ukládá PDF přímo do měsíční externí FDB
|
||||
místo do hlavní medicus.fdb.
|
||||
|
||||
**Funkce:** `zapis_file_ext(vstupconnection, idpac, cesta, souborname, prvnizavorka, soubordate, souborfiledate, poznamka, ext_base_path=r'u:\\')`
|
||||
- Parametry shodné s `funkce.zapis_file()` → jen prohodit import
|
||||
- Vrací `fileid` stejně jako původní funkce
|
||||
|
||||
**Co dělá:**
|
||||
1. Z `soubordate` odvodí `YYYYMM` → `DBNAME = 'DB202603'`
|
||||
2. Načte PDF jako bytes
|
||||
3. Vyhledá EXTERNI_DB pro daný měsíc:
|
||||
- Nalezeno → připojí se k existující FDB (masterkey)
|
||||
- Nenalezeno → vytvoří novou `MEDICUS_FILES_YYYYMM.fdb`, zaregistruje do EXTERNI_DB
|
||||
4. Vygeneruje `UID = uuid.uuid4().hex` (32 znaků)
|
||||
5. Zapíše do DATA tabulky: `UID, DATA (blob), DATASIZE, CHUNK=0`
|
||||
6. Sestaví 48bajtovou BODY referenci
|
||||
7. Získá `fileid` z Gen_Files
|
||||
8. Vloží do FILES s BODY = reference (ne blob)
|
||||
|
||||
### Úprava `s03soubory.py`
|
||||
- Přidán import `funkce_ext`
|
||||
- Volání `funkce.zapis_file(...)` nahrazeno `funkce_ext.zapis_file_ext(...)`
|
||||
|
||||
### BODY reference – binární formát (48 B)
|
||||
```
|
||||
magic 4 B = b'\xee\xbb\xaa\x0b'
|
||||
uid 32 B = UUID4 hex (ASCII, 32 znaků)
|
||||
dblen 4 B = len(DBNAME) jako little-endian uint32
|
||||
dbname N B = DBNAME ASCII (typicky 'DB202603', 8 B)
|
||||
```
|
||||
Celkem typicky: 4 + 32 + 4 + 8 = **48 bajtů**
|
||||
|
||||
### Struktura DATA tabulky (externe DB)
|
||||
```
|
||||
UID VARCHAR(32) NOT NULL
|
||||
DATA BLOB SUB_TYPE 0
|
||||
DATASIZE INTEGER
|
||||
CHUNK INTEGER
|
||||
```
|
||||
Generator: `GEN_UID` (Medicus ho asi nepoužívá přímo, UID je UUID string)
|
||||
|
||||
### EXTERNI_DB tabulka (hlavní DB)
|
||||
```
|
||||
DBNAME např. 'DB202603'
|
||||
SERVER např. 'localhost/3053' (FBScanner proxy)
|
||||
PATH např. 'u:\MEDICUS_FILES_202603.fdb'
|
||||
HESLO šifrované heslo (Medicus AES) – zkopírujeme z existující položky
|
||||
```
|
||||
Při vytváření nové DB: HESLO zkopírujeme z libovolné existující EXTERNI_DB položky
|
||||
(všechny používají masterkey, jen jinak zašifrované – ale stejný klíč).
|
||||
|
||||
### Poznámka k HESLO šifrování
|
||||
Hesla v EXTERNI_DB jsou šifrovaná Medicusem. Při vytváření nové DB proto
|
||||
zkopírujeme HESLO z existující položky (stejné heslo = stejný šifrovaný text).
|
||||
Medicus pak dokáže novou DB otevřít standardně. Pokud by to nefungovalo,
|
||||
lze heslo zadat manuálně přes správce Medicusu.
|
||||
|
||||
## Stav 2026-03-18 – nastudováno po obnově session
|
||||
|
||||
### Co bylo dokončeno (včera večer)
|
||||
- `funkce_ext.zapis_file_ext()` je **otestována a funkční**
|
||||
- `s03soubory.py` volá `zapis_file_ext` místo původní `funkce.zapis_file`
|
||||
- Celý import pipeline funguje end-to-end
|
||||
|
||||
### Celý import pipeline (s03soubory.py)
|
||||
1. Scanuje složku `u:\NextcloudOrdinace\Dokumentace_ke_zpracování`
|
||||
2. Ověří formát názvu souboru: `RC YYYY-MM-DD Jmeno, Jmeno. [prvnizavorka] [druhazavorka].pdf`
|
||||
3. Ověří rodné číslo v KAR tabulce
|
||||
4. Seskupí soubory podle RC (jeden pacient = jeden dekurs)
|
||||
5. Pro každý PDF zavolá `funkce_ext.zapis_file_ext()` → zapíše do externí DB
|
||||
6. Přesune soubor do `u:\NextcloudOrdinace\Dokumentace_zpracovaná`
|
||||
7. Sestaví RTF se záložkami (klikatelné odkazy na soubory v Medicusu)
|
||||
8. Zapíše dekurs do DEKURS tabulky
|
||||
|
||||
### Klíčové soubory
|
||||
- `funkce_ext.py` – zápis PDF do měsíční externí FDB (náhrada za funkce.zapis_file)
|
||||
- `funkce.py` – původní funkce (zapis_file, zapis_dekurs, get_files_id, get_idpac, convert_to1250)
|
||||
- `s03soubory.py` – hlavní import script (spouštět na Windows)
|
||||
- `s04_presun_externi_db.py` – utility: přesun ext DB souborů do u:\externi\ a update PATH v EXTERNI_DB
|
||||
- `test_ext_db4.py` – ověření BODY bajty z FILES tabulky (hex dump)
|
||||
|
||||
### Formát názvu souboru pro import
|
||||
```
|
||||
RC YYYY-MM-DD Prijmeni, Jmeno. [prvnizavorka] [druhazavorka].pdf
|
||||
např: 7309208104 2026-03-17 Buzalka, Vladimír. [EKG] [normální nález].pdf
|
||||
```
|
||||
|
||||
## Oprava RTF klikacích odkazů (2026-03-18)
|
||||
|
||||
### Problém
|
||||
`s03soubory.py` generoval RTF s `\cs22` pro styl odkazu, ale Medicus vyžaduje `\cs32`.
|
||||
Druhý+ bookmark neměl link styling vůbec. `poradi` se nikdy neinkrementoval.
|
||||
|
||||
### Zjištěno analýzou Medicusem vytvořeného DEKURS (ID=263480, AhojClaude.pdf)
|
||||
Správný RTF formát klikacího odkazu:
|
||||
```
|
||||
{\*\cs32\f0\ul\fs20\cf1 Odkaz;} ← stylesheet: cs32, NE cs22
|
||||
\uc1\pard\s10\plain\cs20\f0\i\fs20 Přílohy: {\*\bkmkstart 0}\plain\cs32\f0\ul\fs20\cf1 TEXT{\*\bkmkend 0}\par
|
||||
```
|
||||
- "Přílohy:" je inline s prvním odkazem na stejném `\pard` řádku
|
||||
- Každý další odkaz: `\pard\s10{\*\bkmkstart N}\plain\cs32\f0\ul\fs20\cf1 TEXT{\*\bkmkend N}\par`
|
||||
|
||||
### Opraveno v s03soubory.py + test_import_3files.py
|
||||
1. `\cs22` → `\cs32` v stylesheet i těle RTF
|
||||
2. Header `Vložené přílohy:` je na **samostatném** `\pard` řádku (RTF: `Vlo\'9een\'e9 p\'f8\'edlohy:`)
|
||||
3. Všechny bookmarky mají stejný formát: `\pard\s10{\*\bkmkstart N}\plain\cs32\f0\ul\fs20\cf1 TEXT{\*\bkmkend N}\par`
|
||||
4. Přidáno `poradi += 1` (bug: poradi se nikdy neinkrementoval)
|
||||
5. Odstraněna proměnná `prvnibookmark` – již nepotřebná
|
||||
|
||||
### RTF kódování českých znaků (win1250)
|
||||
- ž = `\'9e`, é = `\'e9`, ř = `\'f8`, í = `\'ed`, á = `\'e1`
|
||||
- "Vložené přílohy:" → `Vlo\'9een\'e9 p\'f8\'edlohy:`
|
||||
|
||||
## Merge do existujícího dekurzu (2026-03-18)
|
||||
|
||||
### Rozhodovací logika (3 případy)
|
||||
1. Poslední dekurs pacienta je z dnešního dne A má `Vložené přílohy:`
|
||||
→ **přidat soubor DO existující sekce** (`pridat_do_sekce_prilohy`)
|
||||
2. Poslední dekurs je z dnešního dne, ale sekci nemá
|
||||
→ **prepend nové sekce na začátek** (`merge_rtf_prepend`)
|
||||
3. Poslední dekurs je z jiného dne / neexistuje
|
||||
→ **nový dekurs pro dnešek**
|
||||
- Funkce: `najdi_posledni_dekurs_dnes(conn, idpac, datum_vlozeni)`
|
||||
|
||||
### pridat_do_sekce_prilohy (přidání do existující sekce)
|
||||
1. Spočítat `"Files:"` v `{\info{\bookmarks}}` = N → nový bkmkstart = N
|
||||
2. Posunout všechny bkmkstart/bkmkend ≥ N o +1 (uvolnit index N)
|
||||
3. Vložit nový `\pard` před `\pard\s10\plain\cs15\f0\fs20 \par` (konec sekce)
|
||||
4. Vložit bookmark na pozici N do `{\info{\bookmarks}}`
|
||||
|
||||
### merge_rtf_prepend (prepend nové sekce)
|
||||
1. Posunout existující `\bkmkstart N` / `\bkmkend N` o počet nových souborů
|
||||
2. Přidat naše bookmarky NA ZAČÁTEK `{\info{\bookmarks ...}}`
|
||||
3. Vložit naše `\pard` tělo PŘED první `\uc1\pard` existujícího těla
|
||||
|
||||
### Detekce sekce
|
||||
- Přítomnost: `PRILOHY_HEADER = r"Vlo\'9een\'e9 p\'f8\'edlohy:"` – hledáme v RTF
|
||||
- Konec sekce: `PRILOHY_CLOSING = r'\pard\s10\plain\cs15\f0\fs20 \par'`
|
||||
|
||||
### Skripty
|
||||
- `test_import_merge.py` – 3 soubory → merge do dnešního dekurzu (bez sekce přílohy)
|
||||
- `test_import_single.py` – 1 soubor → merge DO existující sekce přílohy
|
||||
- `test_import_3files.py` – 3 soubory → vždy nový dekurs (bez merge logiky, starší)
|
||||
|
||||
### Stav testování (2026-03-18)
|
||||
- `test_import_3files.py` ✅ ověřeno – klikací odkazy fungují, "Vložené přílohy:" správně
|
||||
- `test_import_merge.py` – připraveno, nespuštěno
|
||||
- `test_import_single.py` – připraveno, nespuštěno
|
||||
|
||||
### TODO – integrace do s03soubory.py
|
||||
- Přidat `najdi_posledni_dekurs_dnes()` do s03soubory.py
|
||||
- Přidat `pridat_do_sekce_prilohy()` a `merge_rtf_prepend()` do s03soubory.py
|
||||
- Nahradit přímý INSERT DEKURS rozhodovací logikou (3 případy)
|
||||
- Pozn: s03soubory.py má starý `prvnibookmark=True` blok – odstranit (relikt)
|
||||
|
||||
## Další postup (nápady)
|
||||
- Napsat `rtf_to_text()` pro extrakci čistého textu z dekurzů
|
||||
- Prozkoumat tabulky: LECH/LECD (léky?), POU (poukazy?), AMBULEKY (výkony?)
|
||||
|
||||
Reference in New Issue
Block a user