notebookvb
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
# Fakturace a dávky – poznámky pro Clauda
|
||||
|
||||
## Přehled tabulek
|
||||
|
||||
### FAK – faktury pojišťovnám
|
||||
- **844 záznamů** (k 2026-03-28)
|
||||
- Primární klíč: `ID`
|
||||
|
||||
| Sloupec | Popis |
|
||||
|---|---|
|
||||
| `ID` | primární klíč |
|
||||
| `CISFAK` | číslo faktury (10 znaků) |
|
||||
| `POJ` | pojišťovna (3 znaky, např. 111=VZP, 205=ČPZP, 207=OZP) |
|
||||
| `ICZ`, `ICZ1` | IČZ ordinace |
|
||||
| `IDICZ` | FK → ICZ.IDICZ (jen jedna ordinace, neřešit) |
|
||||
| `PORCISLO` | pořadové číslo |
|
||||
| `DATUMOD`, `DATUMDO` | období faktury (od–do) |
|
||||
| `DATVYS` | datum vystavení |
|
||||
| `DATODE` | datum odeslání |
|
||||
| `OBDOB` | období (5 znaků, např. "20260") |
|
||||
| `VYKONY` | částka za výkony (Kč) |
|
||||
| `KAPITACE` | kapitační platba (Kč) |
|
||||
| `ZALOHA` | záloha |
|
||||
| `CENA` | celková cena faktury (Kč) |
|
||||
| `DRUH` | druh faktury (např. "konečná") |
|
||||
| `TYP` | typ (1 znak) |
|
||||
| `ROK` | rok |
|
||||
| `SPLAT` | datum splatnosti |
|
||||
| `PROPLACENO` | datum proplacení (NULL = nezaplaceno) |
|
||||
| `ZAPLACENO` | zaplacená částka |
|
||||
| `ZUM` | ? |
|
||||
| `HOSPAUSAL` | hospitalizační/paušální? |
|
||||
| `FDAVKA` | BLOB – odkaz na dávku |
|
||||
| `KAPDETAIL`, `AGRDETAIL` | BLOBy – detaily kapitace/agregace |
|
||||
| `NAZFAK`, `POZFAK`, `OBDFAK` | název, poznámka, období faktury (texty) |
|
||||
| `ICO`, `BANKA`, `UCET` | IČO, banka, účet |
|
||||
| `ODJMENO/ULICE/MISTO/PSC` | adresa odesílatele |
|
||||
| `PLNAZEV/ULICE/MISTO/PSC` | adresa plátce (pojišťovny) |
|
||||
| `DRUHPOJ` | druh pojištění |
|
||||
|
||||
---
|
||||
|
||||
### FAKDET – finanční detail faktury
|
||||
- **1021 záznamů**
|
||||
- Vazba: `IDFAK` → FAK.ID
|
||||
- Typicky 1–2 řádky na fakturu (breakdown podle lékaře/IDUZI)
|
||||
|
||||
| Sloupec | Popis |
|
||||
|---|---|
|
||||
| `ID` | primární klíč |
|
||||
| `IDFAK` | FK → FAK.ID |
|
||||
| `ICP` | IČP ordinace (např. 09305001) |
|
||||
| `ODB` | odbornost (001 = praktický lékař) |
|
||||
| `IDUZI` | FK → UZIVATEL.IDUZI – který lékař |
|
||||
| `CENAVYK` | výkony (Kč) |
|
||||
| `CENALEC` | léky (Kč) |
|
||||
| `CENAKAP` | kapitace (Kč) |
|
||||
|
||||
**Poznámka:** IDUZI=0 = systémový záznam (kapitace bez konkrétního lékaře).
|
||||
|
||||
---
|
||||
|
||||
### FAKDAV – dávky zahrnuté ve faktuře
|
||||
- **1296 záznamů**
|
||||
- Vazba: `IDFAK` → FAK.ID
|
||||
|
||||
| Sloupec | Popis |
|
||||
|---|---|
|
||||
| `ID` | primární klíč |
|
||||
| `IDFAK` | FK → FAK.ID |
|
||||
| `CISDAV` | číslo dávky |
|
||||
| `DRUH` | druh dávky |
|
||||
| `CENA` | celková cena dávky |
|
||||
| `CENAVYK` | výkony |
|
||||
| `CENALEC` | léky |
|
||||
| `CENAPAU` | paušál |
|
||||
| `ODB` | odbornost |
|
||||
| `ICP` | IČP |
|
||||
|
||||
---
|
||||
|
||||
### PORTAL – elektronické podání pojišťovně
|
||||
- **180 záznamů**
|
||||
- Vazba: `IDFAK` → FAK.ID
|
||||
|
||||
| Sloupec | Popis |
|
||||
|---|---|
|
||||
| `ID` | primární klíč |
|
||||
| `IDFAK` | FK → FAK.ID |
|
||||
| `ODESLANO` | timestamp odeslání |
|
||||
| `DATA`, `KDAVKA`, `FDAVKA` | BLOBy – pravděpodobně XML dávky |
|
||||
| `CHYBA` | příznak chyby (1 znak) |
|
||||
| `STAV` | stav podání (smallint) |
|
||||
| `ID_PODANI` | ID podání u pojišťovny (32 znaků, UUID) |
|
||||
| `IDPODANI` | interní ID podání |
|
||||
| `IDCERT` | certifikát použitý pro podání |
|
||||
| `DAVKA_ROK`, `DAVKA_DISK`, `DAVKA_IDICZ` | metadata dávky |
|
||||
| `BB_DAVKA`, `BB_FAKTURA` | ? |
|
||||
| `DAVKA_DATUMOD`, `DAVKA_DATUMDO` | období dávky |
|
||||
| `DAVKA_CASTKA` | částka dávky |
|
||||
|
||||
---
|
||||
|
||||
## Schéma vazeb
|
||||
|
||||
```
|
||||
FAK (faktura)
|
||||
├── FAKDET (IDFAK → FAK.ID) – finanční breakdown podle lékaře
|
||||
├── FAKDAV (IDFAK → FAK.ID) – seznam dávek ve faktuře
|
||||
├── PORTAL (IDFAK → FAK.ID) – viz níže, IDFAK bývá NULL
|
||||
└── ICZ (IDICZ → ICZ.IDICZ) – ordinace (jen jedna, neřešit)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UZIVATEL – lékaři a uživatelé
|
||||
|
||||
| IDUZI | Příjmení | Jméno | Zkratka | Aktivní |
|
||||
|---|---|---|---|---|
|
||||
| 2 | Jourová | Jana | JOU | F (neaktivní) |
|
||||
| 3 | Sestra | — | SES | F (neaktivní) |
|
||||
| 4 | Buzalková | Michaela | MBU | T – **lékařka, manželka** |
|
||||
| 5 | Ševčíková | Ivana | ISE | T |
|
||||
| 6 | Buzalka | Vladimír | VBU | T – **uživatel (já)** |
|
||||
|
||||
---
|
||||
|
||||
## Ukázkové záznamy
|
||||
|
||||
### FAK ID=856 (poslední)
|
||||
- Faktura č. 260026, pojišťovna **205 (ČPZP)**, prosinec 2025
|
||||
- Vystavena: 2026-03-12, druh: konečná
|
||||
- VYKONY: 2 528,99 Kč, KAPITACE: 0, CENA: **2 528,99 Kč**
|
||||
- ZAPLACENO: NULL, PROPLACENO: NULL
|
||||
|
||||
FAKDET k FAK ID=856:
|
||||
| ID | IDUZI | CENAVYK | CENALEC | CENAKAP |
|
||||
|---|---|---|---|---|
|
||||
| 1034 | 0 (systém) | 0 | 0 | 1 902,54 |
|
||||
| 1035 | 4 (Buzalková) | 2 528,99 | 0 | 0 |
|
||||
|
||||
### FAK ID=855 (předposlední)
|
||||
- Faktura č. 260026, pojišťovna **207 (OZP)**, prosinec 2025
|
||||
- Vystavena: 2026-03-01, druh: konečná
|
||||
- VYKONY: 85 Kč, KAPITACE: 0, CENA: **85 Kč**
|
||||
- ZAPLACENO: NULL, PROPLACENO: NULL
|
||||
|
||||
FAKDET k FAK ID=855:
|
||||
| ID | IDUZI | CENAVYK | CENALEC | CENAKAP |
|
||||
|---|---|---|---|---|
|
||||
| 1033 | 6 (Buzalka Vladimír) | 85 | 0 | 0 |
|
||||
|
||||
---
|
||||
|
||||
## PORTAL – upřesnění (zjištěno 2026-03-28)
|
||||
|
||||
PORTAL **nesouvisí s fakturací**. Je to samostatná agenda – evidence **registračních dávek** odeslaných pojišťovně.
|
||||
|
||||
### Co PORTAL skutečně je
|
||||
- Medicus přes PORTAL odesílá pojišťovně dávky s přihlášením/odhlášením pacientů k lékaři (MUDr. Buzalková jako praktický lékař)
|
||||
- Bez peněz – čistě administrativní agenda registrací
|
||||
- **IDFAK = NULL** u všech registračních podání (není vazba na fakturu)
|
||||
|
||||
### Klíčové sloupce
|
||||
| Sloupec | Popis |
|
||||
|---|---|
|
||||
| `KDAVKA` | odeslaná dávka – pevný formát (hlavička + řádky I = pacienti, RC, datum) |
|
||||
| `DATA` | odpověď pojišťovny jako XML (`<statuscode>100</statuscode>` = OK) |
|
||||
| `ID_PODANI` | ID přidělené pojišťovnou (např. `D01F260118593316.D01`) |
|
||||
| `DAVKA_DISK` | číslo dávky v roce (sekvenční) |
|
||||
| `DAVKA_ROK` | rok dávky |
|
||||
| `DAVKA_DATUMOD/DO` | období registrací v dávce |
|
||||
| `CHYBA` | F = bez chyby |
|
||||
|
||||
### Ukázka KDAVKA (hlavička dávky)
|
||||
```
|
||||
DP80093050000900202506 15 1 0 0.00180:6.2.46
|
||||
H21109305001 179202506001
|
||||
I 1Příjmení Jméno RC datum_registrace
|
||||
I 2...
|
||||
```
|
||||
|
||||
### Ukázka DATA (odpověď pojišťovny)
|
||||
```xml
|
||||
<ekomunikace timestamp="20260127 063105">
|
||||
<session id="ff59b436-...">
|
||||
<statusline>Přijetí registrací proběhlo úspěšně</statusline>
|
||||
<statuscode>100</statuscode>
|
||||
<idpodani>D01F260118593316.D01</idpodani>
|
||||
</session>
|
||||
</ekomunikace>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PORTAL – dva typy dávek
|
||||
|
||||
### Typ 1 – Registrační dávka (DP80)
|
||||
- KDAVKA začíná `DP80`
|
||||
- **IDFAK = NULL** – bez vazby na fakturu
|
||||
- Bez peněz (`DAVKA_CASTKA` = NULL)
|
||||
- Přihlašuje/odhlašuje pacienty k lékaři (MUDr. Buzalková)
|
||||
- Řádky `I` = pacient (RC, datum registrace)
|
||||
|
||||
### Typ 2 – Výkonová dávka (DP98)
|
||||
- KDAVKA začíná `DP98`
|
||||
- **IDFAK = ID faktury** – napojeno na FAK
|
||||
- Má peníze (`DAVKA_CASTKA`, např. 15 452,91 Kč)
|
||||
- `STAV = 10` (registrační mají NULL)
|
||||
- Obsahuje výkony vykázané pojišťovně za dané období
|
||||
|
||||
**Struktura výkonové dávky (KDAVKA):**
|
||||
```
|
||||
DP98... – hlavička dávky (IČP, rok, měsíc, disk, počet případů, částka)
|
||||
A ... – ambulantní případ (RC pacienta, diagnóza)
|
||||
V ... – výkon (datum, kód výkonu, body)
|
||||
Z ... – ZULP (zvlášť účtovaný léčivý přípravek)
|
||||
L ... – lékový řádek (kód, množství, cena)
|
||||
DP05... – druhá část dávky (prevence / jiný typ)
|
||||
P ... – preventivní prohlídka
|
||||
```
|
||||
|
||||
**Odpověď pojišťovny pro výkonovou dávku:**
|
||||
```xml
|
||||
<statusline>Přijetí faktury proběhlo úspěšně</statusline>
|
||||
<statuscode>100</statuscode>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Poznámky
|
||||
- Faktury jsou vystavovány zvlášť pro každou pojišťovnu
|
||||
- FAKDET má řádky zvlášť pro každého lékaře (IDUZI)
|
||||
- IDUZI=0 v FAKDET = systémový záznam pro kapitaci
|
||||
- Kapitace se v FAK.KAPITACE neukazuje (je 0), ale v FAKDET.CENAKAP ano – nutno ověřit
|
||||
- PORTAL = registrační dávky, nesouvisí s fakturací, IDFAK bývá NULL
|
||||
|
||||
## Kódování KDAVKA/FDAVKA – důležité!
|
||||
|
||||
Dávkové soubory (KDAVKA, FDAVKA) jsou uloženy v **CP852** (DOS Latin-2, prahistorické kódování).
|
||||
|
||||
fdb je čte přes connection charset win1250 a vrací je jako Python `str` (špatně dekódované).
|
||||
|
||||
**Správný postup dekódování:**
|
||||
```python
|
||||
# fdb vrátil string dekódovaný jako win1250 – musíme to zvrátit
|
||||
raw_bytes = s.encode('cp1250', errors='replace')
|
||||
spravny_text = raw_bytes.decode('cp852', errors='replace')
|
||||
```
|
||||
|
||||
- **KDAVKA, FDAVKA** → cp852
|
||||
- **DATA** (XML odpověď pojišťovny) → cp1250 (win1250), fdb dekóduje správně
|
||||
@@ -0,0 +1,316 @@
|
||||
# MedicusWithClaudeSelects – SQL dotazy
|
||||
|
||||
## Registrovaní pacienti
|
||||
|
||||
Přesný select který Medicus používá pro záložku **Registrovaní** (zachycen přes FBScanner, dotaz č. 143).
|
||||
|
||||
### Počet registrovaných pacientů
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM KAR
|
||||
WHERE (vyrazen = 'N')
|
||||
AND EXISTS (
|
||||
SELECT id FROM registr r
|
||||
JOIN icp i ON r.idicp = i.idicp
|
||||
WHERE r.idpac = kar.idpac
|
||||
AND (r.datum <= '2026-03-20')
|
||||
AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= '2026-03-20')
|
||||
AND (r.priznak IN ('V','D','A'))
|
||||
AND (i.icp = '09305001')
|
||||
AND (i.odb = '001')
|
||||
)
|
||||
```
|
||||
|
||||
Vrátí: **1618 pacientů** (ověřit na Windows).
|
||||
|
||||
### Podmínky registrace – vysvětlení
|
||||
|
||||
- `vyrazen = 'N'` – pacient není vyřazen z kartotéky
|
||||
- `r.datum <= dnes` – registrace již začala
|
||||
- `r.datum_zruseni IS NULL OR r.datum_zruseni >= dnes` – registrace dosud platí
|
||||
- `r.priznak IN ('V','D','A')` – aktivní příznak (ne 'Z' = zrušen, ne 'N')
|
||||
- `i.icp = '09305001'` – IČP naší ordinace
|
||||
- `i.odb = '001'` – odbornost praktický lékař
|
||||
|
||||
### Skript pro Python
|
||||
|
||||
Viz `count_registrovani.py` v této složce – spustit na Windows.
|
||||
|
||||
### Plný select Medicusu (seznam pacientů s metadaty)
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
KAR.DATNAR,
|
||||
KAR.IDPAC,
|
||||
KAR.INFORMACE,
|
||||
KAR.INFORMACE_COL,
|
||||
KAR.JMENO,
|
||||
KAR.POHLAVI,
|
||||
GPP.POJ,
|
||||
KAR.POZNAMKA,
|
||||
KAR.PRIJMENI,
|
||||
KAR.PRIJMENI_UP,
|
||||
(SELECT DATUM_REGISTRACE FROM SP_GETREGDAT(kar.IDPAC)) AS REGDATUM,
|
||||
KAR.REGISTROVAL,
|
||||
(SELECT PRIZNAK FROM SP_GETREGDAT(kar.IDPAC)) AS REGPRIZNAK,
|
||||
KAR.RODCIS,
|
||||
KAR.ROZENA,
|
||||
KAR.TITUL,
|
||||
KAR.TITULZA,
|
||||
KAR.TRVOBEC,
|
||||
KAR.TRVPSC,
|
||||
KAR.TRVULICE,
|
||||
KAR.VYRAZEN
|
||||
FROM KAR
|
||||
LEFT JOIN GETPACPOJ(KAR.IDPAC, '2026-03-20') GPP ON GPP.IDPAC = KAR.IDPAC
|
||||
WHERE (vyrazen = 'N')
|
||||
AND EXISTS (
|
||||
SELECT id FROM registr r
|
||||
JOIN icp i ON r.idicp = i.idicp
|
||||
WHERE r.idpac = kar.idpac
|
||||
AND (r.datum <= '2026-03-20')
|
||||
AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= '2026-03-20')
|
||||
AND (r.priznak IN ('V','D','A'))
|
||||
AND (i.icp = '09305001')
|
||||
AND (i.odb = '001')
|
||||
)
|
||||
ORDER BY KAR.PRIJMENI_UP ASC, KAR.RODCIS ASC
|
||||
```
|
||||
|
||||
Poznámka: `GETPACPOJ` a `SP_GETREGDAT` jsou uložené procedury Medicusu –
|
||||
fungují v kontextu Firebird připojení přes SYSDBA/masterkey.
|
||||
|
||||
---
|
||||
|
||||
## Panel pacienta – hlavní UNION dotaz
|
||||
|
||||
Zachycen přes Firebird AuditTrace (`default_trace.log`) při otevření karty pacienta
|
||||
(IDPAC=9733, datum 28.03.2026). Dotaz vrací **28 UNION částí** – každá část má pevnou
|
||||
strukturu sloupců: `ID, VAR1, VAR2, DATE1, DATE2, TIME1, INT1, TEXT1, NUM1, NUM2`.
|
||||
|
||||
Parametry při volání:
|
||||
- `:IDPAC` – ID pacienta (např. 9733)
|
||||
- `:RODCIS` – rodné číslo pacienta (např. '0308020152')
|
||||
- `:DATUM` – dnešní datum ve formátu YYYY-MM-DD (např. '2026-03-28')
|
||||
- `:DATUM_CZ` – dnešní datum ve formátu DD.MM.YYYY (např. '28.03.2026')
|
||||
- `:ROK` – aktuální rok (např. '2026')
|
||||
|
||||
### Mapování UNION části → položka panelu Medicusu
|
||||
|
||||
| ID (UNION část) | Tabulka | Položka v panelu Medicusu |
|
||||
|------------------|--------------------|--------------------------------------------------|
|
||||
| `BalickyPac` | BALICKYPAC | Balíčky pacienta (aktivní/budoucí) |
|
||||
| `Dluh` | PLA / PLADET | Dluh (nezaplacené faktury po splatnosti) |
|
||||
| `SouhlasPac` | HISTDOC / SOUHLASPACSABL | Souhlasy pacienta |
|
||||
| `sCenaVykZUM` | DOKLADD / LECD | Cena výkonů v aktuálním roce (ZUM) |
|
||||
| `Registrl` | KAR | Kdo registroval pacienta |
|
||||
| `OseLekPrak` | KARUZIV_SEL | Ošetřující lékař (odb. 001/002) |
|
||||
| `SledLek` | SLEDLEK | Sledující lékař (specialista) |
|
||||
| `HistDoc` | HISTDOC | Historie dokumentů (posledních 10) |
|
||||
| `LastSms` | SMS | Datum poslední odeslané SMS |
|
||||
| `PozadLekar` | DOKLADH | Požadující lékař (EICZ) z posledního dokladu |
|
||||
| `Prilohy` | FILES | Přílohy pacienta (posledních 10) |
|
||||
| `Objednavky` | OBJOBJ | Objednávky od dnešního dne |
|
||||
| `OseLek` | KARUZIV_SEL | Všichni lékaři přiřazení ke kartě |
|
||||
| `PeProhlidky` | PREH / PREINIH | Preventivní a examinační prohlídky |
|
||||
| `Medikace` | MEDIKACE | Aktuální medikace (platná k dnešku) |
|
||||
| `NextDispenz` | DISPAC / DISSKU | Příští dispenzarizace (s termínem) |
|
||||
| `Dispenz` | DISPAC / DISSKU | Dispenzarizace – všechny záznamy |
|
||||
| `Prohlidky` | PREPRI / PREINIH | Preventivní prohlídky – záznamy |
|
||||
| `NextOck` | OCKPRI / KLK | Příští očkování (plánované) |
|
||||
| `LastVykon` | DOKLADD / DOKLADH | Poslední výkon (kód + datum) |
|
||||
| `LastDekurs` | DEKURS | Poslední dekurz (datum) |
|
||||
| `Karta` | KAR | Informace a poznámka z karty |
|
||||
| `Saldo` | PACIENT_SALDO(SP) | Saldo pacienta (funkce) |
|
||||
| `Anamneza` | ANAMNEZA | Anamnéza + krevní skupina |
|
||||
| `Ockovani` | OCKZAZ | Očkovací záznamy (max 20, seskupeno po látce) |
|
||||
| `NeschopenOd` | NES | Aktuální neschopenka (od – do) |
|
||||
| `Alergie` | ANAMNEZA | Alergie (z posledního záznamu anamnézy) |
|
||||
| `Pojistovna` | ICP / ICZ | IDICP naší ordinace pro pojišťovnu pacienta |
|
||||
|
||||
### SQL dotaz (parametrizovaný)
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
cast('BalickyPac' as varchar(11)) as ID, substring(cast(BPAC.KOD as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(BPAC.CENPASMO as VARCHAR(70)) from 1 for 30) as VAR2, cast(BPAC.DATUMOD as DATE) as DATE1, cast(BPAC.DATUMDO as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from BALICKYPAC BPAC left join SP_BALICKYPAC_PRIZNAK(BPAC.ID, ':DATUM_CZ') PRI on 1 = 1 where BPAC.IDPAC = :IDPAC and PRI.PRIZNAK in ('A', 'B')
|
||||
|
||||
UNION SELECT
|
||||
cast('Dluh' as varchar(11)) as ID, substring(cast(P.MENA as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast((SUM(P.CENA - P.SLEVAC) - (SUM(P.PLATBA) + SUM((COALESCE((select SUM(case ZD.TYP when 'R' then ZD.CELKEM else -ZD.CELKEM end) from PLADET ZD where ZD.IDPLA = P.IDPLA and (ZD.TYP <> P.DOKLADTYP) and (ZD.TYP <> '|') and ((ZD.CENA < 0) or (ZD.TYP = 'R'))), 0))))) as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 FROM PLA P WHERE (P.IDPAC = :IDPAC) AND (P.DOKLADTYP = 'F') AND (P.STORNO IS NULL) AND (P.NENISALDO = 'F') AND ((P.SPLATNOST IS NULL) OR (P.SPLATNOST < ':DATUM')) AND (P.VALID = 'F') GROUP BY P.MENA
|
||||
|
||||
UNION SELECT
|
||||
cast('SouhlasPac' as varchar(11)) as ID, substring(cast(case when S.NAZEV is null then case when H.TYP = 'ZSOUPOS' then 'Souhlas/Nesouhlas s poskytnutím zdravotních služeb nezletilému' when H.TYP = 'ZSOUPOZ' then 'Souhlas zákonného zástupce nezletilého pacienta staršího 15ti let' when H.TYP = 'ZSOUPO2' then 'Nesouhlas s poskytnutím zdravotních služeb - povinné očkování' when H.TYP = 'ZPOSIN2' then 'Určení osoby oprávněné dle zákona o zdravotních službách' when H.TYP = 'OdmPece' then 'Prohlášení o odmítnutí zdravotní péče pacientem - Negativní revers' end else S.NAZEV end as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(H.DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from HISTDOC H left join SOUHLASPACSABL S on H.IDSOUHLASPACSABL = S.ID where H.TYP in ('IndSou', 'ZSOUPOS', 'ZSOUPOZ', 'ZSOUPO2', 'ZPOSIN2', 'OdmPece') and H.IDPACI = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('sCenaVykZUM' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(coalesce(sum(cenabod),0) + coalesce(sum(cenamat),0) as NUMERIC(15,2)) as NUM1, cast((select coalesce(sum(cena),0) from LECD d where d.RODCIS = ':RODCIS' and extract(year from d.DATOSE) = ':ROK' and ((d.KAT is null) or (d.KAT <> 'N')) and exists (select h.IDLEC from LECH h where h.IDLEC = d.IDLEC and h.POJ = '207' and h.ICZ in ('09305001'))) as NUMERIC(15,2)) as NUM2 from DOKLADD d where d.RODCIS = ':RODCIS' and extract(year from d.DATOSE) = ':ROK' and ((d.KAT is null) or (d.KAT <> 'N' and d.KAT <> 'K' and d.KAT <> 'A')) and exists (select h.IDHLAV from DOKLADH h where h.IDHLAV = d.IDHLAV and h.POJ = '207' and h.ICZ in ('09305001'))
|
||||
|
||||
UNION SELECT
|
||||
cast('Registrl' as varchar(11)) as ID, substring(cast(REGISTROVAL as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from KAR where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('OseLekPrak' as varchar(11)) as ID, substring(cast(F_CONCAT(PRIJMENI, F_CONCAT(JMENO, TITUL, ', '), ' ') as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(TITUL2 as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(CAST(ODBORN as INTEGER) as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 FROM KARUZIV_SEL(:IDPAC, 'T') WHERE ODBORN in ('001', '002')
|
||||
|
||||
UNION SELECT
|
||||
cast('SledLek' as varchar(11)) as ID, substring(cast(KOD as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(LEK as VARCHAR(70)) from 1 for 30) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from SLEDLEK where IDPAC = :IDPAC and DATUM <= ':DATUM'
|
||||
|
||||
UNION SELECT
|
||||
first 10 cast('HistDoc' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from HISTDOC where IDPACI = :IDPAC and STAV is NULL and IDZARPR = 2 and IDODDPR = 2 and IDPRACPR = 2
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('LastSms' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(MAX(SENDTIME) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from SMS where PACID = :IDPAC and SENDTIME is not NULL and not(STATUS in (100,1000))
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('PozadLekar' as varchar(11)) as ID, substring(cast(H.EICZ as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(H.EODZ as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DOKLADH H where H.IDHLAV = (select first 1 I.IDHLAV from DOKLADH I where I.RODCIS = ':RODCIS' and I.EICZ is not NULL order by I.IDHLAV desc)
|
||||
|
||||
UNION SELECT
|
||||
first 10 cast('Prilohy' as varchar(11)) as ID, substring(cast(FILENAME as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from FILES where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
first 10 cast('Objednavky' as varchar(11)) as ID, substring(cast(F_CONCAT(U.PRIJMENI, F_CONCAT(U.JMENO, U.TITUL, ', '), ' ') as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(PRAC as VARCHAR(70)) from 1 for 30) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(CAS as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from OBJOBJ O join PRACOVISTE P on (P.ID = O.IDPRAC) join UZIVATEL U on (U.IDUZI = O.IDUZI) where IDPAC = :IDPAC and DATUM >= ':DATUM_CZ'
|
||||
|
||||
UNION SELECT
|
||||
cast('OseLek' as varchar(11)) as ID, substring(cast(F_CONCAT(PRIJMENI, F_CONCAT(JMENO, TITUL, ', '), ' ') as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(TITUL2 as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 FROM KARUZIV_SEL(:IDPAC, 'T')
|
||||
|
||||
UNION SELECT
|
||||
cast('PeProhlidky' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUM as DATE) as DATE1, cast(TERMIN as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from PREH join PREINIH on (PREH.IDPREINI = PREINIH.IDPREINI) where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('Medikace' as varchar(11)) as ID, substring(cast(NAZ as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(PLATI_OD as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from MEDIKACE where IDPAC = :IDPAC and PLATI_OD <= ':DATUM_CZ' and (PLATI_DO >= ':DATUM_CZ' or PLATI_DO is NULL)
|
||||
|
||||
UNION SELECT
|
||||
cast('NextDispenz' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(SKUPINA as VARCHAR(70)) from 1 for 30) as VAR2, cast(PRISTI as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DISPAC join DISSKU on (DISSKU.IDDIS = DISPAC.IDDIS) where IDPAC = :IDPAC and PRISTI is not NULL
|
||||
|
||||
UNION SELECT
|
||||
cast('Dispenz' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(SKUPINA as VARCHAR(70)) from 1 for 30) as VAR2, cast(DATZAR as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DISPAC join DISSKU on (DISSKU.IDDIS = DISPAC.IDDIS) where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('Prohlidky' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from PREPRI join PREINIH on (PREPRI.IDPREINI = PREINIH.IDPREINI) where IDPAC = :IDPAC and datum is not null
|
||||
|
||||
UNION SELECT
|
||||
cast('NextOck' as varchar(11)) as ID, substring(cast(coalesce(NAZ,ZKRATKA) as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUMD as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from OCKPRI o left join KLK k on o.ZKRATKA = k.KOD where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('LastVykon' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, substring(cast(D.KOD as VARCHAR(70)) from 1 for 30) as VAR2, cast(D.DATOSE as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DOKLADD D where D.ID = (select first 1 dd.id from dokladd dd join dokladh dh on (dh.idhlav = dd.idhlav) where dd.rodcis = ':RODCIS' and (dh.hodb = '001' or dh.hodb is null) order by dd.datose desc)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('LastDekurs' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(MAX(DATUM) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DEKURS where IDPAC = :IDPAC and (IDPRAC = 2 or IDPRAC = -1)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Karta' as varchar(11)) as ID, substring(cast(INFORMACE as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(CIZINEC as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(INFORMACE_COL as INTEGER) as INT1, POZNAMKA as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from KAR where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Saldo' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(SALDO as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from PACIENT_SALDO(:IDPAC, 1, 0, 0)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Anamneza' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, substring(cast(KREVSKUP as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, ANAMNEZA as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ANAMNEZA where ID = (select first 1 ID from ANAMNEZA where IDPAC = :IDPAC order by DATUM DESC, ID desc)
|
||||
|
||||
UNION SELECT
|
||||
first 20 cast('Ockovani' as varchar(11)) as ID, substring(cast(ockzaz.LATKA as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(ockzaz.ZKRATKA as VARCHAR(70)) from 1 for 30) as VAR2, cast(max(ockzaz.DATUM) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ockzaz where ockzaz.idpac = :IDPAC group by ockzaz.ZKRATKA, ockzaz.LATKA
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('NeschopenOd' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(MAX(ZACNES) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from NES where (IDPAC = :IDPAC) and (ZACNES <= ':DATUM_CZ') and ((KONNES is NULL) or (KONNES > ':DATUM_CZ')) and (STORNO = 'F')
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Alergie' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, ALERGIE as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ANAMNEZA where IDPAC = :IDPAC and ID = (select first 1 ID from ANAMNEZA where IDPAC = :IDPAC and DATUM <= ':DATUM_CZ' order by DATUM desc, ID desc)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Pojistovna' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(P.IDICP as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ICP P join ICZ Z on (Z.IDICZ = P.IDICZ) where Z.POJ = '207' and P.ODB = '001'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ošetřující lékař pacienta
|
||||
|
||||
### Kde je uložen
|
||||
|
||||
Ošetřující lékař není přímo v tabulce `KAR`. Je uložen v tabulce **`KARUZIV`** a čte se
|
||||
přes stored procedure **`KARUZIV_SEL`**.
|
||||
|
||||
### Tabulka KARUZIV
|
||||
|
||||
Vazba pacient → lékař. Jeden pacient může mít více záznamů (více lékařů/pracovišť).
|
||||
|
||||
| Sloupec | Popis |
|
||||
|------------|-------|
|
||||
| `IDPAC` | FK na KAR – pacient |
|
||||
| `IDLEKAR` | FK na LEKARI – externí lékař (specialista, cizí ordinace) |
|
||||
| `IDUZI` | FK na UZIVATEL – interní uživatel Medicusu (vlastní lékař) |
|
||||
| `IDPRAC` | FK na PRACOVISTE – pracoviště |
|
||||
| `IDODD` | FK na ODDEL – oddělení |
|
||||
| `AUTOMAT` | `'F'` = ručně přiřazen, `'T'` = automaticky |
|
||||
|
||||
Pokud je vyplněn `IDLEKAR` → jde se do tabulky `LEKARI` (cizí lékaři).
|
||||
Pokud je vyplněn `IDUZI` → jde se do tabulky `UZIVATEL` (lékaři v Medicusu).
|
||||
|
||||
### Tabulka REGISTR
|
||||
|
||||
Druhý zdroj – registrace pacienta u lékaře/pojišťovny.
|
||||
|
||||
| Sloupec | Popis |
|
||||
|------------------|-------|
|
||||
| `IDPAC` | FK na KAR |
|
||||
| `IDICP` | FK na ICP – identifikace pracoviště/pojišťovny |
|
||||
| `IDUZI` | FK na UZIVATEL – lékař (nepovinný, dohledává se přes ICP) |
|
||||
| `DATUM` | Datum začátku registrace |
|
||||
| `DATUM_ZRUSENI` | Datum zrušení (NULL = stále platná) |
|
||||
| `PRIZNAK` | `'V'`/`'D'`/`'A'` = aktivní; `'Z'`/`'N'` = zrušená/neaktivní |
|
||||
|
||||
### Stored procedure KARUZIV_SEL(IIDPAC, INCL_AUTOMAT)
|
||||
|
||||
Parametry:
|
||||
- `IIDPAC` – IDPAC pacienta
|
||||
- `INCL_AUTOMAT` – `'T'` = vrátit i automaticky přiřazené, `'F'` = jen ruční
|
||||
|
||||
Vrací sloupce: `ID, IDPAC, IDODD, ODD, IDUZI, IDPRAC, IDLEKAR, AUTOMAT, TITUL, PRIJMENI, JMENO, TITUL2, ODBORN`
|
||||
|
||||
**Logika (3 průchody):**
|
||||
|
||||
1. `KARUZIV` kde `AUTOMAT = 'F'` – ručně přiřazení lékaři
|
||||
2. `KARUZIV` kde `AUTOMAT = 'T'` – automaticky přiřazení (jen pokud `INCL_AUTOMAT = 'T'`)
|
||||
3. `REGISTR` – aktivní registrace (datum platný, `PRIZNAK` ≠ `'Z'`/`'N'`, nezrušená)
|
||||
- přes `IDICP` → `ICP` → `PRACOVISTE` → `PRACUZIV` → `UZIVATEL`
|
||||
|
||||
### Použití v panelu pacienta (UNION dotaz)
|
||||
|
||||
```sql
|
||||
-- Ošetřující lékař praktický (odbornost 001 nebo 002)
|
||||
SELECT ... FROM KARUZIV_SEL(:IDPAC, 'T') WHERE ODBORN in ('001', '002')
|
||||
-- → UNION část ID = 'OseLekPrak'
|
||||
|
||||
-- Všichni lékaři přiřazení ke kartě
|
||||
SELECT ... FROM KARUZIV_SEL(:IDPAC, 'T')
|
||||
-- → UNION část ID = 'OseLek'
|
||||
```
|
||||
|
||||
### Zapojené tabulky (přehled)
|
||||
|
||||
```
|
||||
KAR
|
||||
└── KARUZIV ──► LEKARI (externí lékaři, specialisté)
|
||||
└► UZIVATEL (interní lékaři v Medicusu)
|
||||
└► PRACOVISTE (pracoviště / odbornost)
|
||||
└► ODDEL (oddělení)
|
||||
└── REGISTR ──► ICP (identifikace pracoviště)
|
||||
└► PRACOVISTE ──► PRACUZIV ──► UZIVATEL
|
||||
```
|
||||
|
||||
### Barevné rozlišení v GUI Medicusu
|
||||
|
||||
- **Černá** = záznam pochází z `KARUZIV` (explicitně přiřazený ošetřující lékař, `IDUZI` vyplněno)
|
||||
- **Červená** = záznam pochází z `REGISTR` (registrující lékař – SP vrací `ID = 0 - REGISTR.ID`)
|
||||
- **Červená (ext.)** = záznam z `KARUZIV` kde je vyplněno `IDLEKAR` (externí lékař z tabulky `LEKARI`)
|
||||
|
||||
### Duplikát ošetřujícího lékaře – known issue
|
||||
|
||||
`KARUZIV_SEL` prochází **vždy oba zdroje** (KARUZIV i REGISTR) bez ohledu na to, zda už byl lékař nalezen. Pokud má pacient záznam v KARUZIV (černá) i v REGISTR (červená) se stejným lékařem, zobrazí se **dvakrát**.
|
||||
|
||||
Příčina: SP neobsahuje podmínku „přeskoč REGISTR, pokud KARUZIV již vrátil výsledky".
|
||||
|
||||
**Stav ordinace Buzalková (duben 2026):**
|
||||
- Všech 1620 registrovaných pacientů má v `KARUZIV` záznam IDUZI=4 (Michaela, černá)
|
||||
- 1537 pacientů má v `REGISTR` IDUZI=4 (Michaela, červená) → duplikát
|
||||
- Chování je konzistentní, ale GUI zobrazuje oba řádky – čeká se na vyjádření supportu Medicusu
|
||||
|
||||
**Možná řešení (zatím neaplikováno):**
|
||||
- A) Smazat KARUZIV záznamy → zůstane jen červená z REGISTR (jeden řádek)
|
||||
- B) Nastavit REGISTR.IDUZI zpět na NULL → REGISTR path hledá přes PRACOVISTE (najde Michalu jako první NOSVYK='A') → duplikát stále, ale přes jiný lookup
|
||||
- C) Řešení přes support Medicusu
|
||||
@@ -0,0 +1,83 @@
|
||||
SELECT
|
||||
cast('BalickyPac' as varchar(11)) as ID, substring(cast(BPAC.KOD as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(BPAC.CENPASMO as VARCHAR(70)) from 1 for 30) as VAR2, cast(BPAC.DATUMOD as DATE) as DATE1, cast(BPAC.DATUMDO as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from BALICKYPAC BPAC left join SP_BALICKYPAC_PRIZNAK(BPAC.ID, ':DATUM_CZ') PRI on 1 = 1 where BPAC.IDPAC = :IDPAC and PRI.PRIZNAK in ('A', 'B')
|
||||
|
||||
UNION SELECT
|
||||
cast('Dluh' as varchar(11)) as ID, substring(cast(P.MENA as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast((SUM(P.CENA - P.SLEVAC) - (SUM(P.PLATBA) + SUM((COALESCE((select SUM(case ZD.TYP when 'R' then ZD.CELKEM else -ZD.CELKEM end) from PLADET ZD where ZD.IDPLA = P.IDPLA and (ZD.TYP <> P.DOKLADTYP) and (ZD.TYP <> '|') and ((ZD.CENA < 0) or (ZD.TYP = 'R'))), 0))))) as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 FROM PLA P WHERE (P.IDPAC = :IDPAC) AND (P.DOKLADTYP = 'F') AND (P.STORNO IS NULL) AND (P.NENISALDO = 'F') AND ((P.SPLATNOST IS NULL) OR (P.SPLATNOST < ':DATUM')) AND (P.VALID = 'F') GROUP BY P.MENA
|
||||
|
||||
UNION SELECT
|
||||
cast('SouhlasPac' as varchar(11)) as ID, substring(cast(case when S.NAZEV is null then case when H.TYP = 'ZSOUPOS' then 'Souhlas/Nesouhlas s poskytnutím zdravotních služeb nezletilému' when H.TYP = 'ZSOUPOZ' then 'Souhlas zákonného zástupce nezletilého pacienta staršího 15ti let' when H.TYP = 'ZSOUPO2' then 'Nesouhlas s poskytnutím zdravotních služeb - povinné oèkování' when H.TYP = 'ZPOSIN2' then 'Urèení osoby oprávnìné dle zákona o zdravotních službách' when H.TYP = 'OdmPece' then 'Prohlášení o odmítnutí zdravotní péèe pacientem - Negativní revers' end else S.NAZEV end as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(H.DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from HISTDOC H left join SOUHLASPACSABL S on H.IDSOUHLASPACSABL = S.ID where H.TYP in ('IndSou', 'ZSOUPOS', 'ZSOUPOZ', 'ZSOUPO2', 'ZPOSIN2', 'OdmPece') and H.IDPACI = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('sCenaVykZUM' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(coalesce(sum(cenabod),0) + coalesce(sum(cenamat),0) as NUMERIC(15,2)) as NUM1, cast((select coalesce(sum(cena),0) from LECD d where d.RODCIS = ':RODCIS' and extract(year from d.DATOSE) = ':ROK' and ((d.KAT is null) or (d.KAT <> 'N')) and exists (select h.IDLEC from LECH h where h.IDLEC = d.IDLEC and h.POJ = '207' and h.ICZ in ('09305001'))) as NUMERIC(15,2)) as NUM2 from DOKLADD d where d.RODCIS = ':RODCIS' and extract(year from d.DATOSE) = ':ROK' and ((d.KAT is null) or (d.KAT <> 'N' and d.KAT <> 'K' and d.KAT <> 'A')) and exists (select h.IDHLAV from DOKLADH h where h.IDHLAV = d.IDHLAV and h.POJ = '207' and h.ICZ in ('09305001'))
|
||||
|
||||
UNION SELECT
|
||||
cast('Registrl' as varchar(11)) as ID, substring(cast(REGISTROVAL as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from KAR where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('OseLekPrak' as varchar(11)) as ID, substring(cast(F_CONCAT(PRIJMENI, F_CONCAT(JMENO, TITUL, ', '), ' ') as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(TITUL2 as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(CAST(ODBORN as INTEGER) as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 FROM KARUZIV_SEL(9733, 'T') WHERE ODBORN in ('001', '002')
|
||||
|
||||
UNION SELECT
|
||||
cast('SledLek' as varchar(11)) as ID, substring(cast(KOD as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(LEK as VARCHAR(70)) from 1 for 30) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from SLEDLEK where IDPAC = :IDPAC and DATUM <= ':DATUM'
|
||||
|
||||
UNION SELECT
|
||||
first 10 cast('HistDoc' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from HISTDOC where IDPACI = :IDPAC and STAV is NULL and IDZARPR = 2 and IDODDPR = 2 and IDPRACPR = 2
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('LastSms' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(MAX(SENDTIME) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from SMS where PACID = :IDPAC and SENDTIME is not NULL and not(STATUS in (100,1000))
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('PozadLekar' as varchar(11)) as ID, substring(cast(H.EICZ as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(H.EODZ as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DOKLADH H where H.IDHLAV = (select first 1 I.IDHLAV from DOKLADH I where I.RODCIS = ':RODCIS' and I.EICZ is not NULL order by I.IDHLAV desc)
|
||||
|
||||
UNION SELECT
|
||||
first 10 cast('Prilohy' as varchar(11)) as ID, substring(cast(FILENAME as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from FILES where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
first 10 cast('Objednavky' as varchar(11)) as ID, substring(cast(F_CONCAT(U.PRIJMENI, F_CONCAT(U.JMENO, U.TITUL, ', '), ' ') as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(PRAC as VARCHAR(70)) from 1 for 30) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(CAS as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from OBJOBJ O join PRACOVISTE P on (P.ID = O.IDPRAC) join UZIVATEL U on (U.IDUZI = O.IDUZI) where IDPAC = :IDPAC and DATUM >= ':DATUM_CZ'
|
||||
|
||||
UNION SELECT
|
||||
cast('OseLek' as varchar(11)) as ID, substring(cast(F_CONCAT(PRIJMENI, F_CONCAT(JMENO, TITUL, ', '), ' ') as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(TITUL2 as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 FROM KARUZIV_SEL(9733, 'T')
|
||||
|
||||
UNION SELECT
|
||||
cast('PeProhlidky' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUM as DATE) as DATE1, cast(TERMIN as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from PREH join PREINIH on (PREH.IDPREINI = PREINIH.IDPREINI) where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('Medikace' as varchar(11)) as ID, substring(cast(NAZ as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(PLATI_OD as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from MEDIKACE where IDPAC = :IDPAC and PLATI_OD <= ':DATUM_CZ' and (PLATI_DO >= ':DATUM_CZ' or PLATI_DO is NULL)
|
||||
|
||||
UNION SELECT
|
||||
cast('NextDispenz' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(SKUPINA as VARCHAR(70)) from 1 for 30) as VAR2, cast(PRISTI as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DISPAC join DISSKU on (DISSKU.IDDIS = DISPAC.IDDIS) where IDPAC = :IDPAC and PRISTI is not NULL
|
||||
|
||||
UNION SELECT
|
||||
cast('Dispenz' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(SKUPINA as VARCHAR(70)) from 1 for 30) as VAR2, cast(DATZAR as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DISPAC join DISSKU on (DISSKU.IDDIS = DISPAC.IDDIS) where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
cast('Prohlidky' as varchar(11)) as ID, substring(cast(NAZEV as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUM as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from PREPRI join PREINIH on (PREPRI.IDPREINI = PREINIH.IDPREINI) where IDPAC = :IDPAC and datum is not null
|
||||
|
||||
UNION SELECT
|
||||
cast('NextOck' as varchar(11)) as ID, substring(cast(coalesce(NAZ,ZKRATKA) as VARCHAR(254)) from 1 for 250) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(DATUMD as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from OCKPRI o left join KLK k on o.ZKRATKA = k.KOD where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('LastVykon' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, substring(cast(D.KOD as VARCHAR(70)) from 1 for 30) as VAR2, cast(D.DATOSE as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DOKLADD D where D.ID = (select first 1 dd.id from dokladd dd join dokladh dh on (dh.idhlav = dd.idhlav) where dd.rodcis = ':RODCIS' and (dh.hodb = '001' or dh.hodb is null) order by dd.datose desc)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('LastDekurs' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(MAX(DATUM) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from DEKURS where IDPAC = :IDPAC and (IDPRAC = 2 or IDPRAC = -1)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Karta' as varchar(11)) as ID, substring(cast(INFORMACE as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(CIZINEC as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(INFORMACE_COL as INTEGER) as INT1, POZNAMKA as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from KAR where IDPAC = :IDPAC
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Saldo' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(SALDO as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from PACIENT_SALDO(9733, 1, 0, 0)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Anamneza' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, substring(cast(KREVSKUP as VARCHAR(70)) from 1 for 30) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, ANAMNEZA as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ANAMNEZA where ID = (select first 1 ID from ANAMNEZA where IDPAC=9733 order by DATUM DESC, ID desc)
|
||||
|
||||
UNION SELECT
|
||||
first 20 cast('Ockovani' as varchar(11)) as ID, substring(cast(ockzaz.LATKA as VARCHAR(254)) from 1 for 250) as VAR1, substring(cast(ockzaz.ZKRATKA as VARCHAR(70)) from 1 for 30) as VAR2, cast(max(ockzaz.DATUM) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ockzaz where ockzaz.idpac = :IDPAC group by ockzaz.ZKRATKA, ockzaz.LATKA
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('NeschopenOd' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(MAX(ZACNES) as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from NES where (IDPAC = :IDPAC) and (ZACNES <= ':DATUM_CZ') and ((KONNES is NULL) or (KONNES > ':DATUM_CZ')) and (STORNO = 'F')
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Alergie' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(NULL as INTEGER) as INT1, ALERGIE as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ANAMNEZA where IDPAC = :IDPAC and ID = (select first 1 ID from ANAMNEZA where IDPAC = :IDPAC and DATUM <= ':DATUM_CZ' order by DATUM desc, ID desc)
|
||||
|
||||
UNION SELECT
|
||||
first 1 cast('Pojistovna' as varchar(11)) as ID, cast(NULL as VARCHAR(254)) as VAR1, cast(NULL as VARCHAR(70)) as VAR2, cast(NULL as DATE) as DATE1, cast(NULL as DATE) as DATE2, cast(NULL as TIMESTAMP) as TIME1, cast(P.IDICP as INTEGER) as INT1, NULL as TEXT1, cast(NULL as NUMERIC(15,2)) as NUM1, cast(NULL as NUMERIC(15,2)) as NUM2 from ICP P join ICZ Z on (Z.IDICZ = P.IDICZ) where Z.POJ = '207' and P.ODB = '001'
|
||||
@@ -0,0 +1,27 @@
|
||||
import fdb, datetime
|
||||
|
||||
conn = fdb.connect(
|
||||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||
user='SYSDBA', password='masterkey', charset='win1250')
|
||||
|
||||
cur = conn.cursor()
|
||||
dnes = datetime.date.today().isoformat()
|
||||
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) FROM KAR
|
||||
WHERE (vyrazen = 'N')
|
||||
AND EXISTS (
|
||||
SELECT id FROM registr r
|
||||
JOIN icp i ON r.idicp = i.idicp
|
||||
WHERE r.idpac = kar.idpac
|
||||
AND (r.datum <= ?)
|
||||
AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= ?)
|
||||
AND (r.priznak IN ('V','D','A'))
|
||||
AND (i.icp = '09305001')
|
||||
AND (i.odb = '001')
|
||||
)
|
||||
""", (dnes, dnes))
|
||||
|
||||
pocet = cur.fetchone()[0]
|
||||
print(f'Registrovaných pacientů: {pocet}')
|
||||
conn.close()
|
||||
@@ -0,0 +1,78 @@
|
||||
"""db_bridge_vm.py – VM strana souborového mostu k Medicusu.
|
||||
|
||||
Použití z Linuxu:
|
||||
from db_bridge_vm import query
|
||||
rows, columns = query("SELECT COUNT(*) FROM KAR")
|
||||
print(columns, rows)
|
||||
"""
|
||||
import json, time, os, uuid
|
||||
|
||||
BRIDGE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
REQUEST = os.path.join(BRIDGE_DIR, 'query_request.json')
|
||||
RESPONSE = os.path.join(BRIDGE_DIR, 'query_response.json')
|
||||
|
||||
TIMEOUT_SEC = 30
|
||||
POLL_SEC = 0.3
|
||||
|
||||
|
||||
def query(sql, params=None, timeout=TIMEOUT_SEC):
|
||||
"""Pošle SQL dotaz přes souborový most a vrátí (rows, columns).
|
||||
|
||||
Raises:
|
||||
TimeoutError – watchdog neodpověděl do timeout sekund
|
||||
RuntimeError – Firebird vrátil chybu
|
||||
"""
|
||||
# Smaž případnou starou response
|
||||
if os.path.exists(RESPONSE):
|
||||
os.remove(RESPONSE)
|
||||
|
||||
req_id = uuid.uuid4().hex
|
||||
req = {'id': req_id, 'sql': sql, 'params': params or []}
|
||||
|
||||
with open(REQUEST, 'w', encoding='utf-8') as f:
|
||||
json.dump(req, f, ensure_ascii=False)
|
||||
|
||||
# Čekej na odpověď
|
||||
waited = 0.0
|
||||
while waited < timeout:
|
||||
time.sleep(POLL_SEC)
|
||||
waited += POLL_SEC
|
||||
if os.path.exists(RESPONSE):
|
||||
with open(RESPONSE, 'r', encoding='utf-8') as f:
|
||||
resp = json.load(f)
|
||||
os.remove(RESPONSE)
|
||||
if resp.get('status') == 'error':
|
||||
raise RuntimeError(f"DB chyba: {resp.get('error')}")
|
||||
return resp.get('rows', []), resp.get('columns', [])
|
||||
|
||||
# Timeout – smaž request aby watchdog nezpracoval zastaralý dotaz
|
||||
if os.path.exists(REQUEST):
|
||||
os.remove(REQUEST)
|
||||
raise TimeoutError(f'Watchdog neodpověděl do {timeout}s – běží db_bridge_windows.py?')
|
||||
|
||||
|
||||
def query_print(sql, params=None):
|
||||
"""Spustí dotaz a vypíše výsledek přehledně."""
|
||||
rows, cols = query(sql, params)
|
||||
if not cols:
|
||||
print('(žádné sloupce)')
|
||||
return rows, cols
|
||||
col_w = [max(len(str(c)), max((len(str(r[i])) for r in rows), default=0))
|
||||
for i, c in enumerate(cols)]
|
||||
sep = '+' + '+'.join('-' * (w + 2) for w in col_w) + '+'
|
||||
fmt = '|' + '|'.join(f' {{:<{w}}} ' for w in col_w) + '|'
|
||||
print(sep)
|
||||
print(fmt.format(*cols))
|
||||
print(sep)
|
||||
for row in rows:
|
||||
print(fmt.format(*[str(v) if v is not None else 'NULL' for v in row]))
|
||||
print(sep)
|
||||
print(f'{len(rows)} řádků')
|
||||
return rows, cols
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Rychlý test
|
||||
print('Testuji spojení...')
|
||||
rows, cols = query('SELECT COUNT(*) AS POCET FROM KAR')
|
||||
print(f'OK – pacientů v KAR: {rows[0][0]}')
|
||||
@@ -0,0 +1,90 @@
|
||||
"""db_bridge_windows.py – Windows watchdog pro dotazy z Linux VM.
|
||||
|
||||
Spusť jednou na Windows:
|
||||
python db_bridge_windows.py
|
||||
|
||||
Skript sleduje soubor query_request.json ve stejné složce.
|
||||
Jakmile ho najde, spustí SQL dotaz proti Medicusu a zapíše výsledek
|
||||
do query_response.json. Pak čeká na další dotaz.
|
||||
|
||||
Ukonči: Ctrl+C
|
||||
"""
|
||||
import fdb, json, time, os, traceback, datetime
|
||||
|
||||
# ── Konfigurace ───────────────────────────────────────────────────────────────
|
||||
DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
||||
USER = 'SYSDBA'
|
||||
PASSWORD = 'masterkey'
|
||||
CHARSET = 'win1250'
|
||||
|
||||
BRIDGE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
REQUEST = os.path.join(BRIDGE_DIR, 'query_request.json')
|
||||
RESPONSE = os.path.join(BRIDGE_DIR, 'query_response.json')
|
||||
POLL_SEC = 0.5
|
||||
|
||||
# ── Pomocné funkce ────────────────────────────────────────────────────────────
|
||||
|
||||
def serialize(val):
|
||||
"""Převede Python hodnoty na JSON-serializovatelné typy."""
|
||||
if isinstance(val, (datetime.date, datetime.datetime)):
|
||||
return val.isoformat()
|
||||
if isinstance(val, datetime.time):
|
||||
return val.isoformat()
|
||||
if isinstance(val, bytes):
|
||||
return f'<bytes len={len(val)}>'
|
||||
return val
|
||||
|
||||
|
||||
def run_query(sql, params=None):
|
||||
conn = fdb.connect(dsn=DSN, user=USER, password=PASSWORD, charset=CHARSET)
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute(sql, params or [])
|
||||
columns = [d[0] for d in cur.description] if cur.description else []
|
||||
rows = [[serialize(v) for v in row] for row in cur.fetchall()]
|
||||
return {'status': 'ok', 'columns': columns, 'rows': rows, 'error': None}
|
||||
except Exception as e:
|
||||
return {'status': 'error', 'columns': [], 'rows': [], 'error': str(e)}
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
# ── Hlavní smyčka ─────────────────────────────────────────────────────────────
|
||||
print(f'DB Bridge spuštěn. Sleduju: {REQUEST}')
|
||||
print('Ukončení: Ctrl+C\n')
|
||||
|
||||
while True:
|
||||
try:
|
||||
if os.path.exists(REQUEST):
|
||||
print(f'[{datetime.datetime.now().strftime("%H:%M:%S")}] Přijat dotaz...')
|
||||
|
||||
with open(REQUEST, 'r', encoding='utf-8') as f:
|
||||
req = json.load(f)
|
||||
|
||||
os.remove(REQUEST)
|
||||
|
||||
sql = req.get('sql', '')
|
||||
params = req.get('params', [])
|
||||
req_id = req.get('id', '')
|
||||
|
||||
result = run_query(sql, params)
|
||||
result['id'] = req_id
|
||||
result['sql'] = sql
|
||||
|
||||
with open(RESPONSE, 'w', encoding='utf-8') as f:
|
||||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||
|
||||
if result['status'] == 'ok':
|
||||
print(f' → OK, {len(result["rows"])} řádků')
|
||||
else:
|
||||
print(f' → CHYBA: {result["error"]}')
|
||||
|
||||
time.sleep(POLL_SEC)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('\nDB Bridge ukončen.')
|
||||
break
|
||||
except Exception as e:
|
||||
print(f'Neočekávaná chyba: {e}')
|
||||
traceback.print_exc()
|
||||
time.sleep(2)
|
||||
@@ -0,0 +1,30 @@
|
||||
"""get_kar_sortby_idlist.py – přečte definici stored procedure KAR_SORTBY_IDLIST z Firebirdu.
|
||||
Spustit na Windows.
|
||||
"""
|
||||
import fdb
|
||||
|
||||
conn = fdb.connect(
|
||||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||
user='SYSDBA', password='masterkey', charset='win1250')
|
||||
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT RDB$PROCEDURE_SOURCE FROM RDB$PROCEDURES
|
||||
WHERE RDB$PROCEDURE_NAME = 'KAR_SORTBY_IDLIST'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row and row[0]:
|
||||
print(row[0])
|
||||
else:
|
||||
# Možná je to funkce (FUNCTION), ne procedure
|
||||
cur.execute("""
|
||||
SELECT RDB$FUNCTION_SOURCE FROM RDB$FUNCTIONS
|
||||
WHERE RDB$FUNCTION_NAME = 'KAR_SORTBY_IDLIST'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row and row[0]:
|
||||
print(row[0])
|
||||
else:
|
||||
print("Nenalezeno ani jako PROCEDURE ani jako FUNCTION.")
|
||||
|
||||
conn.close()
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
precti_trace.py – přehledné SQL dotazy z Firebird audit trace logu
|
||||
Čte od konce (nejnovější nahoře).
|
||||
|
||||
Použití:
|
||||
python precti_trace.py # posledních 50 dotazů
|
||||
python precti_trace.py 100 # posledních 100
|
||||
python precti_trace.py 50 SELECT # filtr – jen SELECT dotazy
|
||||
"""
|
||||
|
||||
import re, sys, io
|
||||
|
||||
LOG_PATH = r'C:\Program Files\Firebird\Firebird_2_5_CGM\default_trace.log'
|
||||
SEPARATOR = '-' * 80
|
||||
|
||||
TS_RE = re.compile(r'^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+)\s+\([\w:]+\)\s+(\w+)')
|
||||
ATT_RE = re.compile(r'\(ATT_\d+,\s*([\w]+):')
|
||||
SQL_S_RE = re.compile(r'^-{70,}$')
|
||||
SQL_E_RE = re.compile(r'^\^{70,}$')
|
||||
|
||||
# ── Parametry ──────────────────────────────────────────────────────────────
|
||||
limit = int(sys.argv[1]) if len(sys.argv) > 1 else 50
|
||||
filtr = sys.argv[2].upper() if len(sys.argv) > 2 else ''
|
||||
|
||||
# ── Čtení logu ─────────────────────────────────────────────────────────────
|
||||
with open(LOG_PATH, 'r', encoding='cp1252', errors='replace') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# ── Rozděl log na bloky podle timestamp řádků ──────────────────────────────
|
||||
# Každý blok = od jednoho timestamp řádku do dalšího
|
||||
blocks = [] # (start_line_idx, ts, event, block_lines[])
|
||||
i = 0
|
||||
n = len(lines)
|
||||
|
||||
while i < n:
|
||||
m = TS_RE.match(lines[i].rstrip())
|
||||
if m:
|
||||
ts = m.group(1)
|
||||
event = m.group(2)
|
||||
start = i
|
||||
i += 1
|
||||
block = []
|
||||
while i < n and not TS_RE.match(lines[i].rstrip()):
|
||||
block.append(lines[i].rstrip())
|
||||
i += 1
|
||||
blocks.append((ts, event, block))
|
||||
else:
|
||||
i += 1
|
||||
|
||||
# ── Extrahuj SQL z PREPARE_STATEMENT bloků ─────────────────────────────────
|
||||
results = []
|
||||
|
||||
for ts, event, block in blocks:
|
||||
if event != 'PREPARE_STATEMENT':
|
||||
continue
|
||||
|
||||
# Uživatel
|
||||
user = '?'
|
||||
for line in block:
|
||||
att = ATT_RE.search(line)
|
||||
if att:
|
||||
user = att.group(1)
|
||||
break
|
||||
|
||||
# SQL mezi --- a ^^^
|
||||
sql_lines = []
|
||||
plan_lines = []
|
||||
in_sql = False
|
||||
after_sql = False
|
||||
|
||||
for line in block:
|
||||
if SQL_S_RE.match(line):
|
||||
in_sql = True
|
||||
after_sql = False
|
||||
continue
|
||||
if SQL_E_RE.match(line):
|
||||
in_sql = False
|
||||
after_sql = True
|
||||
continue
|
||||
if in_sql:
|
||||
sql_lines.append(line)
|
||||
elif after_sql and line.startswith('PLAN'):
|
||||
plan_lines.append(line)
|
||||
|
||||
sql = '\n'.join(sql_lines).strip()
|
||||
plan = ' '.join(plan_lines).strip()
|
||||
|
||||
if sql:
|
||||
results.append((ts, user, sql, plan))
|
||||
|
||||
# ── Výstup – nejnovější nahoře ─────────────────────────────────────────────
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
filtered = [r for r in results if filtr in r[2].upper()] if filtr else results
|
||||
filtered = list(reversed(filtered))[:limit]
|
||||
|
||||
print(f'Firebird trace – posledních {len(filtered)} dotazu'
|
||||
+ (f' [filtr: {filtr}]' if filtr else ''))
|
||||
print(SEPARATOR)
|
||||
|
||||
for ts, user, sql, plan in filtered:
|
||||
print(f'[{ts}] {user}')
|
||||
print(sql)
|
||||
if plan:
|
||||
print(f' --> {plan}')
|
||||
print(SEPARATOR)
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"status": "ok",
|
||||
"columns": [
|
||||
"ID",
|
||||
"DATUM",
|
||||
"CAS",
|
||||
"UZIVATEL",
|
||||
"IDPAC",
|
||||
"TABULKA",
|
||||
"IDREC",
|
||||
"AKCE",
|
||||
"DETAIL"
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
2882053,
|
||||
"2026-03-20",
|
||||
"17:43:50.523000",
|
||||
"VBU ",
|
||||
3234,
|
||||
10000,
|
||||
3234,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882052,
|
||||
"2026-03-20",
|
||||
"17:43:46.435000",
|
||||
"VBU ",
|
||||
3234,
|
||||
10000,
|
||||
3234,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882051,
|
||||
"2026-03-20",
|
||||
"17:24:19.777000",
|
||||
"VBU ",
|
||||
4757,
|
||||
10000,
|
||||
4757,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882050,
|
||||
"2026-03-20",
|
||||
"17:24:15.866000",
|
||||
"VBU ",
|
||||
3234,
|
||||
10000,
|
||||
3234,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882049,
|
||||
"2026-03-20",
|
||||
"07:11:41.434000",
|
||||
"VBU ",
|
||||
4757,
|
||||
10000,
|
||||
4757,
|
||||
"V",
|
||||
null
|
||||
]
|
||||
],
|
||||
"error": null,
|
||||
"id": "11859d529a784bedb653030ba60131de",
|
||||
"sql": "SELECT FIRST 5 * FROM LOG ORDER BY ID DESC"
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
# trace_report.py – Excel report z Firebird audit trace logu
|
||||
# Ulozi do u:\Dropbox\!!!Days\Downloads Z230\, smaze predchozi verzi.
|
||||
|
||||
import re, sys, io, os, openpyxl
|
||||
from openpyxl.styles import Font, PatternFill, Alignment
|
||||
from openpyxl.utils import get_column_letter
|
||||
from datetime import datetime
|
||||
|
||||
LOG_PATH = r'C:\Program Files\Firebird\Firebird_2_5_CGM\default_trace.log'
|
||||
OUTPUT_DIR = r'u:\Dropbox\!!!Days\Downloads Z230'
|
||||
|
||||
TS_RE = re.compile(r'^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+)\s+\([\w:]+\)\s+(\w+)')
|
||||
ATT_RE = re.compile(r'\(ATT_\d+,\s*([\w]+):')
|
||||
SQL_S_RE = re.compile(r'^-{70,}$')
|
||||
SQL_E_RE = re.compile(r'^\^{70,}$')
|
||||
|
||||
HEADER_FILL = PatternFill('solid', fgColor='2F5496')
|
||||
HEADER_FONT = Font(bold=True, color='FFFFFF')
|
||||
ZEBRA_FILL = PatternFill('solid', fgColor='DCE6F1')
|
||||
WRAP_TOP = Alignment(wrap_text=True, vertical='top')
|
||||
|
||||
# ── Smazání předchozích verzí ───────────────────────────────────────────────
|
||||
for f in os.listdir(OUTPUT_DIR):
|
||||
if f.endswith('_trace.xlsx'):
|
||||
os.remove(os.path.join(OUTPUT_DIR, f))
|
||||
|
||||
# ── Výstupní soubor ─────────────────────────────────────────────────────────
|
||||
now = datetime.now()
|
||||
filename = now.strftime('%Y-%m-%d_%H-%M-%S') + '_trace.xlsx'
|
||||
out_path = os.path.join(OUTPUT_DIR, filename)
|
||||
|
||||
# ── Čtení logu ─────────────────────────────────────────────────────────────
|
||||
with open(LOG_PATH, 'r', encoding='cp1252', errors='replace') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# ── Rozděl na bloky ─────────────────────────────────────────────────────────
|
||||
blocks = []
|
||||
i, n = 0, len(lines)
|
||||
|
||||
while i < n:
|
||||
m = TS_RE.match(lines[i].rstrip())
|
||||
if m:
|
||||
ts, event = m.group(1), m.group(2)
|
||||
i += 1
|
||||
block = []
|
||||
while i < n and not TS_RE.match(lines[i].rstrip()):
|
||||
block.append(lines[i].rstrip())
|
||||
i += 1
|
||||
blocks.append((ts, event, block))
|
||||
else:
|
||||
i += 1
|
||||
|
||||
# ── Extrahuj SQL z PREPARE_STATEMENT bloků ─────────────────────────────────
|
||||
results = []
|
||||
|
||||
for ts, event, block in blocks:
|
||||
if event != 'PREPARE_STATEMENT':
|
||||
continue
|
||||
|
||||
user = '?'
|
||||
for line in block:
|
||||
att = ATT_RE.search(line)
|
||||
if att:
|
||||
user = att.group(1)
|
||||
break
|
||||
|
||||
sql_lines, plan_lines = [], []
|
||||
in_sql, after_sql = False, False
|
||||
|
||||
for line in block:
|
||||
if SQL_S_RE.match(line):
|
||||
in_sql, after_sql = True, False
|
||||
continue
|
||||
if SQL_E_RE.match(line):
|
||||
in_sql, after_sql = False, True
|
||||
continue
|
||||
if in_sql:
|
||||
sql_lines.append(line)
|
||||
elif after_sql and line.startswith('PLAN'):
|
||||
plan_lines.append(line)
|
||||
|
||||
sql = '\n'.join(sql_lines).strip()
|
||||
plan = ' '.join(plan_lines).strip()
|
||||
|
||||
if sql:
|
||||
# Detekuj typ dotazu
|
||||
first = sql.lstrip().upper()
|
||||
if first.startswith('SELECT'):
|
||||
typ = 'SELECT'
|
||||
elif first.startswith('INSERT'):
|
||||
typ = 'INSERT'
|
||||
elif first.startswith('UPDATE'):
|
||||
typ = 'UPDATE'
|
||||
elif first.startswith('DELETE'):
|
||||
typ = 'DELETE'
|
||||
elif first.startswith('EXECUTE'):
|
||||
typ = 'EXECUTE'
|
||||
else:
|
||||
typ = 'OTHER'
|
||||
|
||||
results.append((ts, user, typ, sql, plan))
|
||||
|
||||
# Nejnovější nahoře
|
||||
results = list(reversed(results))
|
||||
|
||||
# ── Excel ───────────────────────────────────────────────────────────────────
|
||||
wb = openpyxl.Workbook()
|
||||
ws = wb.active
|
||||
ws.title = 'TRACE'
|
||||
|
||||
cols = ['CAS', 'UZIVATEL', 'TYP', 'SQL', 'PLAN']
|
||||
ws.append(cols)
|
||||
|
||||
for i, (ts, user, typ, sql, plan) in enumerate(results, start=2):
|
||||
ws.append([ts, user, typ, sql, plan])
|
||||
if i % 2 == 0:
|
||||
for cell in ws[i]:
|
||||
cell.fill = ZEBRA_FILL
|
||||
for cell in ws[i]:
|
||||
cell.alignment = WRAP_TOP
|
||||
|
||||
# Záhlaví
|
||||
for cell in ws[1]:
|
||||
cell.fill = HEADER_FILL
|
||||
cell.font = HEADER_FONT
|
||||
cell.alignment = Alignment(horizontal='center')
|
||||
|
||||
# Šířky sloupců
|
||||
for col, width in zip(['A','B','C','D','E'], [22, 12, 10, 80, 60]):
|
||||
ws.column_dimensions[col].width = width
|
||||
|
||||
# Výška řádků – SQL může být víceřádkový
|
||||
for row in ws.iter_rows(min_row=2):
|
||||
lines_count = max(row[3].value.count('\n') + 1 if row[3].value else 1, 1)
|
||||
ws.row_dimensions[row[0].row].height = min(lines_count * 15, 120)
|
||||
|
||||
ws.freeze_panes = 'A2'
|
||||
|
||||
# Autofiltr
|
||||
ws.auto_filter.ref = f'A1:E{len(results)+1}'
|
||||
|
||||
wb.save(out_path)
|
||||
sys.stdout.buffer.write(f'Ulozeno: {out_path}\n'.encode('utf-8'))
|
||||
sys.stdout.buffer.write(f'Dotazu: {len(results)}\n'.encode('utf-8'))
|
||||
Reference in New Issue
Block a user