10 KiB
Lékový záznam eRecept → MySQL
Popis pipeline pro stažení lékového záznamu pacienta z eRecept SÚKL API a jeho uložení do relační databáze MySQL.
Soubory
| Soubor | Co dělá |
|---|---|
05UlozitOdpoved.py |
Zavolá SOAP API, stáhne XML odpověď, uloží ji do odpoved_lekovy_zaznam.xml |
06UlozitDoMySQL.py |
Naparsuje uložené XML, vytvoří/přepíše tabulky v MySQL, vloží data |
Typické spuštění
# 1. stáhnout čerstvá data z eReceptu
python 05UlozitOdpoved.py
# 2. uložit do databáze
python 06UlozitDoMySQL.py
# nebo předat jiný XML soubor
python 06UlozitDoMySQL.py C:\cesta\k\jine_odpovedi.xml
Autentizace (eRecept SÚKL, ostrý provoz)
| Parametr | Hodnota |
|---|---|
| Endpoint | https://lekar-soap.erecept.sukl.cz/cuer/Lekar2 |
| mTLS certifikát | AMBSUKL214235369G_31DEC2024.pfx (platnost do 31. 12. 2026) |
| HTTP Basic user | UUID lékaře e08c89c6-2b1a-4eba-8ed9-4e3e63618379 |
| SOAP operace | NacistLekovyZaznam |
| XML namespace | http://www.sukl.cz/erp/201912 |
| Verze zprávy | 202501A |
Certifikát = identifikace ordinace, UUID+heslo = identifikace lékaře jako osoby.
Dotaz — parametry NacistLekovyZaznamLekarDotaz
<Doklad>
<Pristupujici>
<Uzivatel>UUID lékaře</Uzivatel>
<Pracoviste>IČP ordinace</Pracoviste>
</Pristupujici>
<PocetZnakuATC>7</PocetZnakuATC> <!-- 5 nebo 7 -->
<PocetMesicu>60</PocetMesicu> <!-- max 99 -->
<Pacient>
<Totoznost>
<Jmeno><Prijmeni>...</Prijmeni><Jmena>...</Jmena></Jmeno>
<DatumNarozeni>YYYY-MM-DD</DatumNarozeni>
</Totoznost>
</Pacient>
</Doklad>
Struktura XML odpovědi
Dle XSD Cuer2Schema.xsd + CuerSchema.xsd, verze 202501A:
NacistLekovyZaznamOdpoved
├── Doklad
│ ├── Pacient – jméno + datum narození
│ ├── PredepisujiciSeznam – lékaři, kteří předepisovali
│ ├── VydavajiciSeznam – lékárny, kde byl výdej
│ ├── PredpisSeznam
│ │ └── Predpis × N – co bylo předepsáno
│ ├── VydejSeznam
│ │ └── Vydej × N – co bylo vydáno v lékárně
│ └── DuplicitaSeznam – duplicitní výdeje
└── Zprava – metadata odpovědi (ID, čas, verze SW)
Typy léků v Predpis i Vydej
Každý předpis / výdej obsahuje právě jeden z těchto elementů:
| Typ | Popis | Klíčová pole |
|---|---|---|
HVLPReg |
Registrovaný hromadně vyráběný LP | Kod (SÚKL), ATC, Nazev, Forma, Sila, Baleni |
HVLPNereg |
Neregistrovaný HVLP | stejná struktura jako HVLPReg |
IPLP |
Individuálně připravovaný LP (magistraliter) | Nazev, PostupPripravy (receptura), Slozka[] |
INN |
Předpis účinnou látkou (genericky) | Nazev, Forma, Sila, Baleni |
IPLP — dvojí uložení receptury
- Předpis (
PredpisSeznam/Predpis/IPLP): lékař zadal recepturu jako volný text vPostupPripravy. PrvkySlozkazde lékař typicky nevyplňuje. - Výdej (
VydejSeznam/Vydej/IPLP): lékárna při přípravě zaznamenala strukturované složky (Slozkas množstvím, jednotkou a názvem suroviny). Kvalita dat závisí na lékárně — některé rozkládají do detailu (suroviny, obal, taxa laborum), jiné evidují jen 1 ks jako celek.
Databázové schéma — medicus (MySQL 9.6)
Všechny délky a datové typy jsou přesně dle XSD, ne odhady. Varianta B — lék je denormalizován přímo do řádku předpisu/výdeje.
Relační diagram
zprava (1)
├── predpis (N)
│ └── predpis_slozka (N) -- složky IPLP z předpisu
└── vydej (N)
└── vydej_slozka (N) -- složky IPLP z výdeje
vydej.id_lp_predpis → predpis.id_lp_predpis (párování výdeje s předpisem)
Tabulka zprava
Jeden řádek = jedna odpověď API (jedno volání NacistLekovyZaznam).
| Sloupec | Typ | Zdroj v XSD |
|---|---|---|
id_zpravy |
CHAR(36) UNIQUE | zprava_type.ID_Zpravy |
verze |
VARCHAR(20) | zprava_type.Verze |
odeslano |
DATETIME | zprava_type.Odeslano |
aplikace |
VARCHAR(512) | zprava_odpoved_type.Aplikace |
id_podani |
CHAR(36) | zprava_odpoved_type.ID_Podani |
prijato |
DATETIME | zprava_odpoved_type.Prijato |
pacient_prijmeni |
VARCHAR(35) | jmeno_osoby_type.Prijmeni |
pacient_jmena |
VARCHAR(24) | jmeno_osoby_type.Jmena |
pacient_datum_narozeni |
DATE | lz_totoznost_type.DatumNarozeni |
stazeno |
DATETIME | automaticky při INSERT |
Tabulka predpis
Dle lz_nacteni_predepsany_lp_erp_type.
| Sloupec | Typ | NOT NULL | Poznámka |
|---|---|---|---|
id_lp_predpis |
CHAR(36) | ✓ | UUID z eReceptu, globálně unikátní |
kod_predepisujiciho |
VARCHAR(36) | ✓ | UUID lékaře |
datum_vystaveni |
DATE | ✓ | |
mnozstvi |
SMALLINT | ✓ | 1–9999 |
navod |
VARCHAR(80) | ✓ | max 80 znaků dle XSD |
opakovani |
INT | opakování předpisu | |
modry_pruh |
TINYINT(1) | modrý pruh (návykové látky) | |
typ_leku |
ENUM | HVLPReg / HVLPNereg / IPLP / INN | |
lek_kod |
CHAR(7) | kód SÚKL (jen HVLP) | |
atc |
VARCHAR(7) | ATC kód (jen HVLP) | |
nazev |
VARCHAR(200) | max 200 — INN má nejdelší název | |
forma |
VARCHAR(27) | léková forma | |
sila |
VARCHAR(24) | síla přípravku | |
cesta_podani |
VARCHAR(15) | POR, INH, … | |
baleni |
VARCHAR(22) | string, ne číslo (může být "100 ks") | |
postup_pripravy |
VARCHAR(4000) | receptura IPLP jako volný text |
Tabulka predpis_slozka
Dle slozka_iplp_predpis_type. Řádky vznikají jen pro IPLP předpisy se strukturovanými složkami.
| Sloupec | Typ | NOT NULL | Poznámka |
|---|---|---|---|
predpis_id |
INT | ✓ | FK → predpis.id |
mnozstvi |
DECIMAL(15,6) | ✓ | přesné množství suroviny |
jednotka |
ENUM('g','ks') | ✓ | |
nazev |
VARCHAR(200) | ✓ | název suroviny / přípravku |
surovina |
CHAR(7) | kód suroviny v registru SÚKL | |
hvlp_reg |
CHAR(7) | pokud je složka registrovaný HVLP |
Tabulka vydej
Dle lz_nacteni_vydany_lp_erp_type.
| Sloupec | Typ | NOT NULL | Poznámka |
|---|---|---|---|
id_lp_vydej |
CHAR(36) | ✓ | UUID výdeje |
id_lp_predpis |
CHAR(36) | FK → predpis.id_lp_predpis, NULL = výdej bez e-předpisu | |
kod_vydavajiciho |
VARCHAR(36) | ✓ | UUID lékárníka |
datum_vydeje |
DATE | ✓ | |
mnozstvi |
DECIMAL(6,2) | ✓ | desetinné — např. 0.5 balení |
navod |
VARCHAR(80) | ✓ | |
exspirace |
DATE | exspirace šarže | |
sarze |
VARCHAR(50) | ✓ | číslo šarže |
seriove_cislo |
VARCHAR(20) | sériové číslo (léky s el. sledováním) | |
pozn |
VARCHAR(1000) | poznámka lékárníka | |
typ_leku |
ENUM | HVLPReg / HVLPNereg / IPLP | |
lek_kod |
CHAR(7) | kód SÚKL (HVLP) nebo KodVZP (IPLP) | |
atc |
VARCHAR(7) | jen HVLP | |
nazev |
VARCHAR(146) | ||
forma |
VARCHAR(27) | ||
sila |
VARCHAR(24) | ||
cesta_podani |
VARCHAR(15) | ||
postup_pripravy |
VARCHAR(4000) | receptura IPLP |
Tabulka vydej_slozka
Dle slozka_iplp_type. Jako predpis_slozka, ale navíc obsahuje hrazeno_zp.
| Sloupec | Typ | NOT NULL | Poznámka |
|---|---|---|---|
vydej_id |
INT | ✓ | FK → vydej.id |
mnozstvi |
DECIMAL(15,6) | ✓ | |
jednotka |
ENUM('g','ks') | ✓ | |
nazev |
VARCHAR(200) | ✓ | název suroviny |
hrazeno_zp |
DECIMAL(9,2) | částka hrazená zdravotní pojišťovnou | |
surovina |
CHAR(7) | ||
hvlp_reg |
CHAR(7) |
Klíčové vlastnosti importu (06UlozitDoMySQL.py)
- Idempotentní:
INSERT IGNOREnaid_lp_predpis/id_lp_vydej— opakované spuštění se stejným XML nepřidá duplikáty. - Víc pacientů:
zprava.id_zpravyje UNIQUE — každé volání API (jiný pacient, jiný čas) vytvoří nový řádek vzprava. Předpisy a výdeje napříč pacienty se agregují vpredpis/vydej. - Schema se přepisuje:
vytvor_schema()vždy DROPne a znovu vytvoří všech 5 tabulek. Při produkčním použití (více pacientů) tuto část odstraňte a spouštějte DDL jen jednou při inicializaci.
Užitečné analytické dotazy
-- nejčastěji předepisované ATC skupiny za posledních 12 měsíců
SELECT atc, nazev, COUNT(*) AS pocet, MAX(datum_vystaveni) AS naposledy
FROM predpis
WHERE datum_vystaveni >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
GROUP BY atc, nazev
ORDER BY pocet DESC;
-- co bylo předepsáno ale nevyzvednuto
SELECT p.datum_vystaveni, p.nazev, p.atc, p.navod
FROM predpis p
LEFT JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis
WHERE v.id_lp_vydej IS NULL;
-- IPLP magistraliter — kompletní receptury s frekvencí
SELECT p.nazev, p.postup_pripravy,
COUNT(*) AS pocet_predpisu
FROM predpis p
WHERE p.typ_leku = 'IPLP'
GROUP BY p.nazev, p.postup_pripravy
ORDER BY pocet_predpisu DESC;
-- IPLP výdeje — strukturované složky (kde je lékárna zadala)
SELECT v.datum_vydeje, v.nazev AS pripravek,
GROUP_CONCAT(s.mnozstvi, ' ', s.jednotka, ' ', s.nazev
ORDER BY s.id SEPARATOR ' + ') AS slozeni
FROM vydej v
JOIN vydej_slozka s ON s.vydej_id = v.id
WHERE v.typ_leku = 'IPLP'
GROUP BY v.id
ORDER BY v.datum_vydeje DESC;
-- nejčastěji používané suroviny v magistrech (ze strany výdeje)
SELECT nazev, jednotka, COUNT(*) AS pocet
FROM vydej_slozka
GROUP BY nazev, jednotka
ORDER BY pocet DESC;
-- párování: co předepsal lékař vs. co lékárna vydala (generická záměna)
SELECT p.datum_vystaveni,
p.nazev AS predepsano, p.atc,
v.nazev AS vydano, v.datum_vydeje
FROM predpis p
JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis
WHERE p.nazev <> v.nazev;
Závislosti (Python)
requests
requests-pkcs12
pymysql
pip install requests requests-pkcs12 pymysql
XSD zdroje
Schéma verze 202501A, soubory v Dokumentace/2025-04-24/WSDL_XSD/NEPRIORITNI_WEBOVE_SLUZBY/:
| Soubor | Obsah |
|---|---|
Cuer2Schema.xsd |
Typy specifické pro lékový záznam: NacistLekovyZaznamOdpoved, lz_nacteni_predepsany_lp_erp_type, lz_nacteni_vydany_lp_erp_type, slozka_iplp_* |
CuerSchema.xsd |
Společné typy: hvlp_type, zprava_odpoved_type, zprava_type, jmeno_osoby_type, jednotka |