Files
recept/NačteníPředpisuWithClaude/NacistPredpis_DOKUMENTACE.md
2026-04-16 14:20:38 +02:00

11 KiB
Raw Permalink Blame History

NacistPredpis — Funkční SOAP klient pro IS eRecept SÚKL

Pipeline pro stažení detailu jednotlivých receptů z eRecept SÚKL API. Doplňuje existující hromadný lékový záznam (NacistLekovyZaznam) o údaje, které hromadný dotaz nevrací.


Soubory

Soubor Co dělá
NacistPredpis_FUNKCNI.py Stáhne detail jednoho receptu dle hardcoded ID_Dokladu (ruční test)
08StahnoutPredpisy.py Starší skript bez DB integrace — nahrazen 10_StahnoutXML.py
09_VytvorTabulky.py Vytvoří tabulky recept_doklad a recept_plp v MySQL
10_StahnoutXML.py Stahování — načte ERP kódy z Medicusu, přeskočí terminální, uloží XML
11_ParseXML.py Parsování — naparsuje XML archiv a uloží data do MySQL
NačteníPředpisuWithClaude/
├── NacistPredpis_FUNKCNI.py          ← test jednoho receptu
├── 08StahnoutPredpisy.py             ← starší skript (bez DB)
├── 09_VytvorTabulky.py               ← DDL MySQL tabulek
├── 10_StahnoutXML.py                 ← hromadné stahování s přeskakováním
├── 11_ParseXML.py                    ← parsování XML do MySQL
├── NacistPredpis_DOKUMENTACE.md      ← tento soubor
├── xml_archive/                      ← archiv XML odpovědí (YYYY-MM-DD/ERP_KOD.xml)
├── MedicusDebug/                     ← zachycené SOAP požadavky z Medicusu
└── Tests/                            ← starší vývojové soubory

Co NacistPredpis vrací navíc oproti NacistLekovyZaznam

Hromadný lékový záznam (NacistLekovyZaznam, endpoint /cuer/Lekar2) vrací seznam předpisů a výdejů za pacienta, ale bez detailů o receptu jako celku.

NacistPredpis (endpoint /cuer/Lekar, namespace 201704) vrací detail jednoho konkrétního receptu, včetně:

Údaje o receptu (dokladu)

Pole Popis
ID_Dokladu Alfanumerický kód receptu (např. PPIBVF93285E)
Stav Stav receptu: PREDEPSANY, CASTECNE_VYDANY, PLNE_VYDANY, ZRUSENY
PlatnostDo Datum konce platnosti receptu
VypisDo Prodloužení platnosti výpisem
Akutni Příznak akutní péče
Rodina „Pro potřebu rodiny" / ad usum proprium
Opakovani Počet výdejů u opakovacích receptů
DruhPojisteni VEREJNE / OSTATNI
ModryPruh Omamné/psychotropní látky
Pozn Poznámka na receptu (max 1000 znaků)
ZapocitatelnyDoplatekZbyvaDoLimitu Zbývá do limitu doplatků pacienta
Zmena / Zalozeni Datetime poslední změny / vytvoření

Údaje o úhradě léku (per PLP)

Pole Popis
Uhrada ZAKLADNI / ZVYSENA / NEHRAZENY / PACIENT
Prekroceni Překročení limitu

Údaje o pacientovi

Pole Popis
CP Číslo pojištěnce (rodné číslo)
ZP Zdravotní pojišťovna (kód + název)
Adresa Kompletní adresa pacienta
Pohlavi M / F (ne M/Z jak uvádí XSD — reálně posíláno M/F)
Telefon Telefonní číslo
Notifikace SMS / Email

Údaje o předepisujícím

Pole Popis
Lekar.Kod UUID lékaře — nebo "skryto" (ukládáme jako NULL)
Odbornost Kód + název (např. 001 — všeobecné praktické lékařství)
Email Email lékaře

Zkrácený výdej

Odpověď obsahuje i sekci Vydej[] se zkrácenou informací o výdejích — název lékárny, jméno lékárníka (často „skryto"), datum vydeje, vydané léky.


Porovnání operací

NacistPredpis NacistLekovyZaznam
Namespace 201704 201912
Endpoint /cuer/Lekar /cuer/Lekar2
SOAPAction NacistPredpis NacistLekovyZaznam
Identifikace ID_Dokladu (alfanumerický kód receptu) jméno + datum narození pacienta
Výsledek detail jednoho receptu celý lékový záznam pacienta (roky)
Velikost odpovědi ~3.54.5 KB ~227 KB
Pokrytí pouze naše ordinace (ERP kód z Medicusu) všichni lékaři pacienta

Autentizace (stejná jako u všech operací eReceptu)

Parametr Hodnota
Endpoint https://lekar-soap.erecept.sukl.cz/cuer/Lekar
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 NacistPredpis
XML namespace http://www.sukl.cz/erp/201704
Verze zprávy 202501A

Certifikát se hledá relativně ke skriptu: ../../AMBSUKL214235369G_31DEC2024.pfx


Zdroj ID_Dokladu — Medicus (Firebird)

Alfanumerický kód receptu (ID_Dokladu) není v hromadném lékovém záznamu. Nachází se v tabulce RECEPT_EPODANI v Medicusu:

RECEPT.id_epodani  →  RECEPT_EPODANI.id
RECEPT_EPODANI.erp  =  ID_Dokladu  (např. "PPIBVF93285E")

Důsledek: Detaily receptů lze stáhnout pouze pro naši ordinaci. O předpisech cizích lékařů víme jen to, co vrací lékový záznam.

SQL dotaz

SELECT DISTINCT ep.erp, r.datum, r.lek, r.dop,
       TRIM(kar.prijmeni) AS prijmeni, TRIM(kar.jmeno) AS jmeno
FROM recept r
JOIN recept_epodani ep ON r.id_epodani = ep.id
JOIN kar ON r.idpac = kar.idpac
WHERE r.datum >= '2025-01-01' AND ep.erp IS NOT NULL
ORDER BY r.datum DESC

Pozor: LIMIT v 10_StahnoutXML.py omezuje počet řádků z Firebirdu před deduplikací. Po deduplikaci (jeden recept = více léků = více řádků) může být výsledný počet receptů nižší.

Statistika (duben 2026)

  • 13 571 receptů s ERP kódem od 1. 1. 2025
  • 13 578 receptů celkem (7 bez ERP kódu — papírové/neodeslané)

Databázové schéma — MySQL

Relační diagram

recept_doklad (1)  ──────────────────  (N)  recept_plp
  id_dokladu PK                               id_lp PK  ──────►  predpis.id_lp_predpis
                                              id_dokladu FK

Tabulka recept_plp.id_lp = predpis.id_lp_predpis — přímý JOIN s lékovým záznamem.

Tabulka recept_doklad

Jeden řádek na celý recept (ID_Dokladu).

Sloupec Typ Poznámka
id_dokladu VARCHAR(20) PK ERP kód
stav ENUM PREDEPSANY / PRIPRAVOVANY / CASTECNE_VYDANY / PLNE_VYDANY / ZRUSENY
stav_terminal TINYINT(1) 1 = nepotřebuje další stahování
datum_vystaveni DATE
platnost_do DATE
vypis_do DATE prodloužení výpisem
akutni TINYINT(1)
rodina TINYINT(1) ad usum proprium
opakovani INT NULL = není opakovací
druh_pojisteni ENUM VEREJNE / OSTATNI / POJISTENI_EU
modry_pruh TINYINT(1)
pozn VARCHAR(1000)
zap_doplatek DECIMAL(10,2) ZapocitatelnyDoplatekZbyvaDoLimitu
zalozeni / zmena DATETIME z eReceptu
lekar_kod CHAR(36) UUID lékaře; NULL pokud "skryto"
odbornost_kod / odbornost_nazev VARCHAR
lekar_email VARCHAR(100)
cp VARCHAR(10) číslo pojištěnce
zp_kod / zp_nazev VARCHAR pojišťovna při předpisu (snapshot)
pac_telefon VARCHAR(20)
pac_notifikace ENUM SMS / EMAIL
pac_pohlavi VARCHAR(5) M / F
xml_soubor VARCHAR(255) cesta k poslednímu XML
stazeno DATETIME poslední aktualizace

Tabulka recept_plp

Jeden řádek na PLP položku (lék na receptu).

Sloupec Typ Poznámka
id_lp CHAR(36) PK UUID = predpis.id_lp_predpis
id_dokladu VARCHAR(20) FK
uhrada VARCHAR(20) ZAKLADNI / ZVYSENA / NEHRAZENY / PACIENT
prekroceni TINYINT(1)

JOIN lékový záznam + detail receptu

SELECT p.datum_vystaveni, p.nazev, p.atc, p.navod,
       rd.stav, rd.platnost_do, rd.zp_nazev,
       rp.uhrada,
       v.datum_vydeje
FROM predpis p
LEFT JOIN recept_plp    rp ON rp.id_lp       = p.id_lp_predpis
LEFT JOIN recept_doklad rd ON rd.id_dokladu  = rp.id_dokladu
LEFT JOIN vydej          v ON v.id_lp_predpis = p.id_lp_predpis
WHERE p.atc LIKE 'C09%'
ORDER BY p.datum_vystaveni DESC;

LEFT JOIN — pro cizí lékaře rd a rp budou NULL (nemáme jejich ERP kód).


10_StahnoutXML.py — stahování

Parametry (editovat přímo v souboru)

DATUM_OD = "2025-01-01"   # recepty od tohoto data
LIMIT    = None            # max počet receptů; None = bez omezení

Logika přeskakování

Na začátku načte z MySQL jeden dotaz:

SELECT id_dokladu FROM recept_doklad WHERE stav_terminal = 1

Výsledek = Python set. Pro každý ERP kód z Medicusu:

  • je v setu → přeskočit (vydaný / zrušený / expirovaný)
  • není v setu → stáhnout

Stornované recepty jsou filtrovány přímo v dotazu do Firebirdu (AND r.STORNO = 'F'), takže se pro ně SOAP volání na SÚKL vůbec neprovádí.

Co je terminální (stav_terminal = 1)

  • stav IN ('PLNE_VYDANY', 'ZRUSENY')
  • nebo platnost_do < dnes (expirovaný bez vyzvednutí)

Ošetření chyb

Kód Popis Chování
D003 Předpis zrušen lékařem Uloží _CHYBA.xml, pokračuje
HTTP 500 SOAP Fault Uloží _CHYBA.xml, pokračuje
Exception Síťová chyba Vypíše EXCEPTION, pokračuje

11_ParseXML.py — parsování do MySQL

Parametry (editovat přímo v souboru)

DATUM_FILTR = None    # např. "2026-04-14", nebo None = celý archiv

Co dělá

  1. Načte z MySQL {id_dokladu: xml_soubor} pro všechny již zpracované záznamy
  2. Najde nejnovější XML pro každý ERP kód (nejvyšší datum v adresářové struktuře)
  3. Přeskočí soubory, jejichž cesta se nezměnila oproti DB — zpracuje jen nově stažené
  4. Naparsuje stav, platnost, pacient, předepisující, PLP položky
  5. recept_doklad: INSERT ... ON DUPLICATE KEY UPDATE (stav se může změnit)
  6. recept_plp: INSERT IGNORE (UUID je stabilní)

Správné pořadí spuštění

10_StahnoutXML.py  →  11_ParseXML.py  →  10_StahnoutXML.py  →  ...

10 se spoléhá na stav_terminal v MySQL, který nastavuje 11. Bez spuštění 11 budou terminální recepty znovu stahovány.


Ověřeno (16. 4. 2026)

  • Hromadné stažení od 1. 1. 2025 dokončeno (LIMIT = None)
  • Staženo 9 616 receptů (po filtraci stornovaných z Firebirdu)
  • 11_ParseXML.py přeskakuje nezměněné soubory — opakované spuštění zpracuje jen nově stažené

XSD zdroje

Schéma verze 202501A, soubory v Dokumentace/2025-04-24/WSDL_XSD/:

Soubor Obsah
PRIORITNI_WEBOVE_SLUZBY/schema1.xsd NacteniPredpisuDotaz, identifikace_dokladu_type, nacteni_predpisu_erp_odpoved_type
NEPRIORITNI_WEBOVE_SLUZBY/CuerSchema.xsd hvlp_type, zprava_type, jmeno_osoby_type