Přidán podprojekt Recepty (eRecept SÚKL)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vladimir Buzalka
2026-04-19 07:06:17 +02:00
parent a59a565586
commit adb84523cd
11334 changed files with 113692 additions and 0 deletions
@@ -0,0 +1,78 @@
import uuid
from datetime import datetime, timezone
from pathlib import Path
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
# --- Konfigurace ---
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINT = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar2"
PRIJMENI = "Buzalka"
JMENA = "Vladimír"
DATUM_NAROZENI = "1973-09-20"
POCET_ZNAKU_ATC = 7
POCET_MESICU =60
VYSTUP = Path(__file__).parent / "odpoved_lekovy_zaznam.xml"
def nacist_a_ulozit():
sess = Session()
sess.mount("https://", Pkcs12Adapter(
pkcs12_filename=PFX_FILE,
pkcs12_password=PFX_PASSWORD
))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
f'<NacistLekovyZaznamLekarDotaz xmlns="http://www.sukl.cz/erp/201912">'
f'<Doklad>'
f'<Pristupujici><Uzivatel>{UZIVATEL}</Uzivatel><Pracoviste>{PRACOVISTE}</Pracoviste></Pristupujici>'
f'<PocetZnakuATC>{POCET_ZNAKU_ATC}</PocetZnakuATC>'
f'<PocetMesicu>{POCET_MESICU}</PocetMesicu>'
f'<Pacient><Totoznost><Jmeno><Prijmeni>{PRIJMENI}</Prijmeni><Jmena>{JMENA}</Jmena></Jmeno>'
f'<DatumNarozeni>{DATUM_NAROZENI}</DatumNarozeni></Totoznost></Pacient>'
f'</Doklad>'
f'<Zprava><ID_Zpravy>{id_zpravy}</ID_Zpravy><Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano><SW_Klienta>MEDICUS_____</SW_Klienta></Zprava>'
f'</NacistLekovyZaznamLekarDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"',
"User-Agent": "Medicus"
}
print(f"POST {ENDPOINT} ...")
resp = sess.post(ENDPOINT, data=soap_body.encode("utf-8"), headers=headers, timeout=30)
print(f"HTTP {resp.status_code} | {len(resp.content)} bytů")
if resp.status_code == 200:
VYSTUP.write_text(resp.text, encoding="utf-8")
print(f"Uloženo: {VYSTUP}")
else:
print("CHYBA — odpověď neuložena")
print(resp.text)
if __name__ == "__main__":
nacist_a_ulozit()
@@ -0,0 +1,765 @@
"""
Nacte odpoved lekoveho zaznamu (XML) a ulozi ji do MySQL.
Schema: pacient / zprava / predpis / predpis_slozka / vydej / vydej_slozka / predepisujici / vydavajici
Typy a delky presne dle XSD (Cuer2Schema.xsd + CuerSchema.xsd, verze 202501A)
Spusteni (jednorazova inicializace + import jednoho XML):
python 06UlozitDoMySQL.py
nebo:
python 06UlozitDoMySQL.py cesta/k/odpoved.xml
Pro hromadne stazeni vsech pacientu pouzij 07StahnoutVsechny.py.
"""
import sys
from pathlib import Path
import xml.etree.ElementTree as ET
import pymysql
import pymysql.cursors
# ── konfigurace ───────────────────────────────────────────────────────────────
XML_SOUBOR = Path(__file__).parent / "odpoved_lekovy_zaznam.xml"
DB = dict(
host = "192.168.1.76",
user = "root",
password = "Vlado9674+",
database = "medicus",
charset = "utf8mb4",
cursorclass = pymysql.cursors.DictCursor,
)
NS = "http://www.sukl.cz/erp/201912"
# ─────────────────────────────────────────────────────────────────────────────
def t(el, tag):
"""Prvni potomek s danym tagem → text nebo None."""
found = el.find(f"{{{NS}}}{tag}")
return found.text.strip() if found is not None and found.text else None
def datum(s):
return s[:10] if s else None
def ts(s):
return s[:19].replace("T", " ") if s else None
# ── DDL ───────────────────────────────────────────────────────────────────────
# Pouziva se ve vytvor_schema() (DROP + CREATE) pro ciste spusteni
DDL_DROP = [
"DROP TABLE IF EXISTS predpis_slozka",
"DROP TABLE IF EXISTS vydej_slozka",
"DROP TABLE IF EXISTS vydej",
"DROP TABLE IF EXISTS predpis",
"DROP TABLE IF EXISTS zprava",
"DROP TABLE IF EXISTS pacient",
"DROP TABLE IF EXISTS predepisujici",
"DROP TABLE IF EXISTS vydavajici",
]
DDL_CREATE = [
# ── pacient ───────────────────────────────────────────────────────────────
# Zrcadlo registrovanych pacientu z Medicusu (Firebird).
# idpac = IDPAC z KAR tabulky Medicusu.
# poznamka: posledni chyba API (napr. "neztotozneny pacient"); NULL = OK
"""
CREATE TABLE IF NOT EXISTS pacient (
id INT AUTO_INCREMENT PRIMARY KEY,
idpac INT NOT NULL UNIQUE,
prijmeni VARCHAR(35) NOT NULL,
jmena VARCHAR(24),
datum_narozeni DATE NOT NULL,
aktivni TINYINT(1) NOT NULL DEFAULT 1,
poznamka VARCHAR(500),
INDEX idx_prijmeni (prijmeni)
) ENGINE=InnoDB
""",
# ── zprava ────────────────────────────────────────────────────────────────
# zprava_odpoved_type + zprava_type:
# ID_Zpravy CHAR(36), Verze, Odeslano dateTime
# Aplikace(512), ID_Podani CHAR(36), Prijato dateTime
# jmeno_osoby_type: Prijmeni(35), Jmena(24)
# pacient_id: FK na pacient.id (NULL pokud volano z 06 primo)
# xml_soubor: relativni cesta k ulozene XML odpovedi
"""
CREATE TABLE IF NOT EXISTS zprava (
id INT AUTO_INCREMENT PRIMARY KEY,
id_zpravy CHAR(36) NOT NULL UNIQUE,
pacient_id INT,
verze VARCHAR(20),
odeslano DATETIME,
aplikace VARCHAR(512),
id_podani CHAR(36),
prijato DATETIME,
pacient_prijmeni VARCHAR(35),
pacient_jmena VARCHAR(24),
pacient_datum_narozeni DATE,
xml_soubor VARCHAR(255),
stazeno DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (pacient_id) REFERENCES pacient(id) ON DELETE SET NULL,
INDEX idx_pacient_id (pacient_id),
INDEX idx_pacient (pacient_prijmeni, pacient_datum_narozeni)
) ENGINE=InnoDB
""",
# ── predpis ───────────────────────────────────────────────────────────────
# lz_nacteni_predepsany_lp_erp_type:
# ID_LP_Predpis CHAR(36) NOT NULL, KodPredepisujiciho(36) NOT NULL,
# DatumVystaveni date NOT NULL, Mnozstvi int(1-9999) NOT NULL,
# Navod(80) NOT NULL, Opakovani int?, ModryPruh boolean?
# lek — vzdy jen jeden z: HVLPReg / HVLPNereg / IPLP / INN
# hvlp_type: Kod CHAR(7)?, ATC(7)?, Nazev(146)!, Forma(27)?,
# Sila(24)?, CestaPodani(15)?, Baleni VARCHAR(22)?
# inn_predpis_type: Nazev(200) — nejdelsi nazev mezi typy
# iplp_predpis_type: PostupPripravy(4000), Nazev(146), CestaPodani(15), Forma(27)
"""
CREATE TABLE IF NOT EXISTS predpis (
id INT AUTO_INCREMENT PRIMARY KEY,
zprava_id INT NOT NULL,
id_lp_predpis CHAR(36) NOT NULL UNIQUE,
kod_predepisujiciho VARCHAR(36) NOT NULL,
datum_vystaveni DATE NOT NULL,
mnozstvi SMALLINT NOT NULL,
navod VARCHAR(80) NOT NULL,
opakovani INT,
modry_pruh TINYINT(1),
typ_leku ENUM('HVLPReg','HVLPNereg','IPLP','INN'),
lek_kod CHAR(7),
atc VARCHAR(7),
nazev VARCHAR(200),
forma VARCHAR(27),
sila VARCHAR(24),
cesta_podani VARCHAR(15),
baleni VARCHAR(22),
postup_pripravy VARCHAR(4000),
FOREIGN KEY (zprava_id) REFERENCES zprava(id) ON DELETE CASCADE,
INDEX idx_atc (atc),
INDEX idx_datum (datum_vystaveni)
) ENGINE=InnoDB
""",
# ── predpis_slozka ────────────────────────────────────────────────────────
# slozka_iplp_predpis_type:
# Mnozstvi DECIMAL(15,6) NOT NULL, Jednotka ENUM('g','ks') NOT NULL,
# Nazev(200) NOT NULL, Surovina CHAR(7)?, HVLPReg CHAR(7)?
"""
CREATE TABLE IF NOT EXISTS predpis_slozka (
id INT AUTO_INCREMENT PRIMARY KEY,
predpis_id INT NOT NULL,
mnozstvi DECIMAL(15,6) NOT NULL,
jednotka ENUM('g','ks') NOT NULL,
nazev VARCHAR(200) NOT NULL,
surovina CHAR(7),
hvlp_reg CHAR(7),
FOREIGN KEY (predpis_id) REFERENCES predpis(id) ON DELETE CASCADE,
INDEX idx_nazev (nazev)
) ENGINE=InnoDB
""",
# ── vydej ─────────────────────────────────────────────────────────────────
# lz_nacteni_vydany_lp_erp_type:
# Mnozstvi DECIMAL(6,2) NOT NULL, Navod(80) NOT NULL,
# Sarze(50) NOT NULL, SerioveCislo(20)?, Pozn(1000)?
# lek — vzdy jen jeden z: HVLPReg / HVLPNereg / IPLP
# iplp_type (vydej): KodVZP CHAR(7)?, PostupPripravy(4000), Nazev(146), CestaPodani(15)
"""
CREATE TABLE IF NOT EXISTS vydej (
id INT AUTO_INCREMENT PRIMARY KEY,
zprava_id INT NOT NULL,
id_lp_vydej CHAR(36) NOT NULL UNIQUE,
id_lp_predpis CHAR(36),
kod_vydavajiciho VARCHAR(36) NOT NULL,
datum_vydeje DATE NOT NULL,
mnozstvi DECIMAL(6,2) NOT NULL,
navod VARCHAR(80) NOT NULL,
exspirace DATE,
sarze VARCHAR(50) NOT NULL,
seriove_cislo VARCHAR(20),
pozn VARCHAR(1000),
typ_leku ENUM('HVLPReg','HVLPNereg','IPLP'),
lek_kod CHAR(7),
atc VARCHAR(7),
nazev VARCHAR(146),
forma VARCHAR(27),
sila VARCHAR(24),
cesta_podani VARCHAR(15),
postup_pripravy VARCHAR(4000),
FOREIGN KEY (zprava_id) REFERENCES zprava(id) ON DELETE CASCADE,
FOREIGN KEY (id_lp_predpis) REFERENCES predpis(id_lp_predpis) ON DELETE SET NULL,
INDEX idx_predpis (id_lp_predpis),
INDEX idx_atc (atc),
INDEX idx_datum (datum_vydeje)
) ENGINE=InnoDB
""",
# ── vydej_slozka ──────────────────────────────────────────────────────────
# slozka_iplp_type:
# Mnozstvi DECIMAL(15,6) NOT NULL, Jednotka ENUM('g','ks') NOT NULL,
# Nazev(200) NOT NULL, HrazenoZP DECIMAL(9,2)?,
# Surovina CHAR(7)?, HVLPReg CHAR(7)?
"""
CREATE TABLE IF NOT EXISTS vydej_slozka (
id INT AUTO_INCREMENT PRIMARY KEY,
vydej_id INT NOT NULL,
mnozstvi DECIMAL(15,6) NOT NULL,
jednotka ENUM('g','ks') NOT NULL,
nazev VARCHAR(200) NOT NULL,
hrazeno_zp DECIMAL(9,2),
surovina CHAR(7),
hvlp_reg CHAR(7),
FOREIGN KEY (vydej_id) REFERENCES vydej(id) ON DELETE CASCADE,
INDEX idx_nazev (nazev)
) ENGINE=InnoDB
""",
# ── predepisujici ─────────────────────────────────────────────────────────
# PredepisujiciSeznam > Predepisujici:
# Lekar: Kod CHAR(36), Jmeno: Prijmeni(35), Jmena(24)
# ICZ CHAR(8)?, ICP CHAR(8)?
# PZS: Nazev(200), Adresa: NazevUlice, CisloPopisne, CisloOrientacni, NazevObce, PSC
# Telefon(20)?
# lekar_kod = predpis.kod_predepisujiciho
"""
CREATE TABLE IF NOT EXISTS predepisujici (
id INT AUTO_INCREMENT PRIMARY KEY,
lekar_kod CHAR(36) NOT NULL UNIQUE,
prijmeni VARCHAR(35),
jmena VARCHAR(24),
icz CHAR(8),
icp CHAR(8),
pzs_nazev VARCHAR(200),
ulice VARCHAR(150),
mesto VARCHAR(100),
psc CHAR(5),
telefon VARCHAR(20),
INDEX idx_icp (icp),
INDEX idx_icz (icz)
) ENGINE=InnoDB
""",
# ── vydavajici ────────────────────────────────────────────────────────────
# VydavajiciSeznam > Vydavajici:
# Lekarnik: Kod CHAR(36), Jmeno: Prijmeni(35), Jmena(24)
# PZS: Nazev(200), Telefon(20)?, Adresa: NazevUlice, CisloPopisne, CisloOrientacni, NazevObce, PSC
# lekarnik_kod = vydej.kod_vydavajiciho
"""
CREATE TABLE IF NOT EXISTS vydavajici (
id INT AUTO_INCREMENT PRIMARY KEY,
lekarnik_kod CHAR(36) NOT NULL UNIQUE,
prijmeni VARCHAR(35),
jmena VARCHAR(24),
pzs_nazev VARCHAR(200),
ulice VARCHAR(150),
mesto VARCHAR(100),
psc CHAR(5),
telefon VARCHAR(20)
) ENGINE=InnoDB
""",
]
def vytvor_schema(conn):
"""DROP + CREATE vsech tabulek. Pouzij pro ciste spusteni / reset dat."""
with conn.cursor() as cur:
for stmt in DDL_DROP:
cur.execute(stmt)
for stmt in DDL_CREATE:
stmt = stmt.strip()
if stmt:
cur.execute(stmt)
conn.commit()
print("Schema OK — tabulky smazany a vytvoreny znovu")
def inicializuj_schema(conn):
"""CREATE TABLE IF NOT EXISTS — bezpecne pro opakowane spusteni (neznici data)."""
with conn.cursor() as cur:
for stmt in DDL_CREATE:
stmt = stmt.strip()
if stmt:
cur.execute(stmt)
# Zpetna kompatibilita: pridat sloupec poznamka pokud jeste neexistuje
cur.execute("""
SELECT COUNT(*) AS cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'pacient'
AND COLUMN_NAME = 'poznamka'
""")
if cur.fetchone()["cnt"] == 0:
cur.execute(
"ALTER TABLE pacient ADD COLUMN poznamka VARCHAR(500) NULL DEFAULT NULL"
)
conn.commit()
# ── parsovani predepisujicich a vydavajicich ─────────────────────────────────
def _parsuj_adresu(pzs_el):
"""Ze elementu PZS vraci (ulice, mesto, psc)."""
adr = pzs_el.find(f"{{{NS}}}Adresa") if pzs_el is not None else None
if adr is None:
return None, None, None
ulice_parts = [
t(adr, "NazevUlice") or "",
t(adr, "CisloPopisne") or "",
t(adr, "CisloOrientacni") or "",
]
ulice = " ".join(p for p in ulice_parts if p).strip() or None
psc = t(adr, "PSC")
if psc and len(psc) > 5:
psc = psc[:5]
return ulice, t(adr, "NazevObce"), psc
def parsuj_predepisujici(doklad):
"""Vraci seznam slovniku pro tabulku predepisujici."""
seznam = []
sez_el = doklad.find(f"{{{NS}}}PredepisujiciSeznam")
if sez_el is None:
return seznam
for el in sez_el.findall(f"{{{NS}}}Predepisujici"):
lekar = el.find(f"{{{NS}}}Lekar")
if lekar is None:
continue
jmeno = lekar.find(f"{{{NS}}}Jmeno")
pzs = el.find(f"{{{NS}}}PZS")
ulice, mesto, psc = _parsuj_adresu(pzs)
seznam.append(dict(
lekar_kod = t(lekar, "Kod"),
prijmeni = t(jmeno, "Prijmeni") if jmeno is not None else None,
jmena = t(jmeno, "Jmena") if jmeno is not None else None,
icz = t(el, "ICZ"),
icp = t(el, "ICP"),
pzs_nazev = t(pzs, "Nazev") if pzs is not None else None,
ulice = ulice,
mesto = mesto,
psc = psc,
telefon = t(el, "Telefon"),
))
return seznam
def parsuj_vydavajici(doklad):
"""Vraci seznam slovniku pro tabulku vydavajici."""
seznam = []
sez_el = doklad.find(f"{{{NS}}}VydavajiciSeznam")
if sez_el is None:
return seznam
for el in sez_el.findall(f"{{{NS}}}Vydavajici"):
lekarnik = el.find(f"{{{NS}}}Lekarnik")
if lekarnik is None:
continue
jmeno = lekarnik.find(f"{{{NS}}}Jmeno")
pzs = el.find(f"{{{NS}}}PZS")
ulice, mesto, psc = _parsuj_adresu(pzs)
seznam.append(dict(
lekarnik_kod = t(lekarnik, "Kod"),
prijmeni = t(jmeno, "Prijmeni") if jmeno is not None else None,
jmena = t(jmeno, "Jmena") if jmeno is not None else None,
pzs_nazev = t(pzs, "Nazev") if pzs is not None else None,
ulice = ulice,
mesto = mesto,
psc = psc,
telefon = t(pzs, "Telefon") if pzs is not None else None,
))
return seznam
# ── parsovani leku ────────────────────────────────────────────────────────────
def parsuj_slozky_predpis(lek_el):
"""Ze IPLP elementu vraci seznam slovniku pro predpis_slozka."""
slozky = []
for s in lek_el.findall(f"{{{NS}}}Slozka"):
slozky.append(dict(
mnozstvi = t(s, "Mnozstvi"),
jednotka = t(s, "Jednotka"),
nazev = t(s, "Nazev"),
surovina = t(s, "Surovina"),
hvlp_reg = t(s, "HVLPReg"),
))
return slozky
def parsuj_slozky_vydej(lek_el):
"""Ze IPLP elementu vraci seznam slovniku pro vydej_slozka."""
slozky = []
for s in lek_el.findall(f"{{{NS}}}Slozka"):
slozky.append(dict(
mnozstvi = t(s, "Mnozstvi"),
jednotka = t(s, "Jednotka"),
nazev = t(s, "Nazev"),
hrazeno_zp = t(s, "HrazenoZP"),
surovina = t(s, "Surovina"),
hvlp_reg = t(s, "HVLPReg"),
))
return slozky
def parsuj_lek_predpis(p):
"""Vraci (lek_fields dict, slozky list).
Typ leku: HVLPReg / HVLPNereg / IPLP / INN — vzdy jen jeden.
"""
for typ in ("HVLPReg", "HVLPNereg"):
lek = p.find(f"{{{NS}}}{typ}")
if lek is not None:
return dict(
typ_leku = typ,
lek_kod = t(lek, "Kod"),
atc = t(lek, "ATC"),
nazev = t(lek, "Nazev"),
forma = t(lek, "Forma"),
sila = t(lek, "Sila"),
cesta_podani = t(lek, "CestaPodani"),
baleni = t(lek, "Baleni"),
postup_pripravy = None,
), []
lek = p.find(f"{{{NS}}}IPLP")
if lek is not None:
return dict(
typ_leku = "IPLP",
lek_kod = None,
atc = None,
nazev = t(lek, "Nazev"),
forma = t(lek, "Forma"),
sila = None,
cesta_podani = t(lek, "CestaPodani"),
baleni = None,
postup_pripravy = t(lek, "PostupPripravy"),
), parsuj_slozky_predpis(lek)
lek = p.find(f"{{{NS}}}INN")
if lek is not None:
return dict(
typ_leku = "INN",
lek_kod = None,
atc = None,
nazev = t(lek, "Nazev"),
forma = t(lek, "Forma"),
sila = t(lek, "Sila"),
cesta_podani = t(lek, "CestaPodani"),
baleni = t(lek, "Baleni"),
postup_pripravy = None,
), []
return dict(typ_leku=None, lek_kod=None, atc=None, nazev=None,
forma=None, sila=None, cesta_podani=None,
baleni=None, postup_pripravy=None), []
def parsuj_lek_vydej(v):
"""Vraci (lek_fields dict, slozky list).
Typ leku: HVLPReg / HVLPNereg / IPLP — vzdy jen jeden.
"""
for typ in ("HVLPReg", "HVLPNereg"):
lek = v.find(f"{{{NS}}}{typ}")
if lek is not None:
return dict(
typ_leku = typ,
lek_kod = t(lek, "Kod"),
atc = t(lek, "ATC"),
nazev = t(lek, "Nazev"),
forma = t(lek, "Forma"),
sila = t(lek, "Sila"),
cesta_podani = t(lek, "CestaPodani"),
postup_pripravy = None,
), []
lek = v.find(f"{{{NS}}}IPLP")
if lek is not None:
return dict(
typ_leku = "IPLP",
lek_kod = t(lek, "KodVZP"),
atc = None,
nazev = t(lek, "Nazev"),
forma = None,
sila = None,
cesta_podani = t(lek, "CestaPodani"),
postup_pripravy = t(lek, "PostupPripravy"),
), parsuj_slozky_vydej(lek)
return dict(typ_leku=None, lek_kod=None, atc=None, nazev=None,
forma=None, sila=None, cesta_podani=None,
postup_pripravy=None), []
# ── parsovani XML ─────────────────────────────────────────────────────────────
def parsuj_xml(xml_soubor):
tree = ET.parse(xml_soubor)
root = tree.getroot()
odpoved = root[0][0] # Envelope > Body > NacistLekovyZaznamOdpoved
# Doklad prvni, Zprava druha — presne dle XSD sequence
doklad = odpoved.find(f"{{{NS}}}Doklad")
zpr = odpoved.find(f"{{{NS}}}Zprava")
# ── Zprava ───────────────────────────────────────────────────────────────
zprava = dict(
id_zpravy = t(zpr, "ID_Zpravy"),
verze = t(zpr, "Verze"),
odeslano = ts(t(zpr, "Odeslano")),
aplikace = t(zpr, "Aplikace"),
id_podani = t(zpr, "ID_Podani"),
prijato = ts(t(zpr, "Prijato")),
)
# ── Pacient ───────────────────────────────────────────────────────────────
pac = doklad.find(f"{{{NS}}}Pacient")
jmeno = pac.find(f"{{{NS}}}Jmeno")
zprava["pacient_prijmeni"] = t(jmeno, "Prijmeni") if jmeno is not None else None
zprava["pacient_jmena"] = t(jmeno, "Jmena") if jmeno is not None else None
zprava["pacient_datum_narozeni"] = datum(t(pac, "DatumNarozeni"))
# ── Predpisy ──────────────────────────────────────────────────────────────
predpisy = [] # kazda polozka: (row_dict, slozky_list)
predpis_seznam = doklad.find(f"{{{NS}}}PredpisSeznam")
if predpis_seznam is not None:
for p in predpis_seznam.findall(f"{{{NS}}}Predpis"):
row = dict(
id_lp_predpis = t(p, "ID_LP_Predpis"),
kod_predepisujiciho = t(p, "KodPredepisujiciho"),
datum_vystaveni = datum(t(p, "DatumVystaveni")),
mnozstvi = t(p, "Mnozstvi"),
navod = t(p, "Navod"),
opakovani = t(p, "Opakovani"),
modry_pruh = t(p, "ModryPruh"),
)
lek_fields, slozky = parsuj_lek_predpis(p)
row.update(lek_fields)
predpisy.append((row, slozky))
# ── Vydeji ────────────────────────────────────────────────────────────────
vydeji = [] # kazda polozka: (row_dict, slozky_list)
vydej_seznam = doklad.find(f"{{{NS}}}VydejSeznam")
if vydej_seznam is not None:
for v in vydej_seznam.findall(f"{{{NS}}}Vydej"):
row = dict(
id_lp_vydej = t(v, "ID_LP_Vydej"),
id_lp_predpis = t(v, "ID_LP_Predpis"),
kod_vydavajiciho = t(v, "KodVydavajiciho"),
datum_vydeje = datum(t(v, "DatumVydeje")),
mnozstvi = t(v, "Mnozstvi"),
navod = t(v, "Navod"),
exspirace = datum(t(v, "Exspirace")),
sarze = t(v, "Sarze"),
seriove_cislo = t(v, "SerioveCislo"),
pozn = t(v, "Pozn"),
)
lek_fields, slozky = parsuj_lek_vydej(v)
row.update(lek_fields)
vydeji.append((row, slozky))
predepisujici = parsuj_predepisujici(doklad)
vydavajici = parsuj_vydavajici(doklad)
return zprava, predpisy, vydeji, predepisujici, vydavajici
# ── ulozeni do DB ─────────────────────────────────────────────────────────────
def _najdi_id(cur, tabulka, sloupec, hodnota):
"""Pomocna funkce — vrati id radku dle unikatniho sloupce."""
cur.execute(f"SELECT id FROM {tabulka} WHERE {sloupec} = %s", (hodnota,))
row = cur.fetchone()
return row["id"] if row else None
def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
pacient_id=None, xml_soubor=None):
"""
Ulozi parsovana data do MySQL.
pacient_id — FK na tabulku pacient (None pokud volano primo z 06)
xml_soubor — relativni cesta k archivnimu XML souboru (None pokud neni archivovano)
Vraci dict se statistikami:
predpisy_novych, predpisy_celkem,
vydeji_novych, vydeji_celkem,
predpis_slozka, vydej_slozka
"""
iplp_predpisu = 0
iplp_vydejuu = 0
with conn.cursor() as cur:
# ── zprava ────────────────────────────────────────────────────────────
zprava_row = dict(zprava)
zprava_row["pacient_id"] = pacient_id
zprava_row["xml_soubor"] = xml_soubor
cur.execute("""
INSERT INTO zprava
(id_zpravy, pacient_id, verze, odeslano, aplikace, id_podani, prijato,
pacient_prijmeni, pacient_jmena, pacient_datum_narozeni, xml_soubor)
VALUES
(%(id_zpravy)s, %(pacient_id)s, %(verze)s, %(odeslano)s, %(aplikace)s,
%(id_podani)s, %(prijato)s,
%(pacient_prijmeni)s, %(pacient_jmena)s, %(pacient_datum_narozeni)s,
%(xml_soubor)s)
ON DUPLICATE KEY UPDATE
prijato = VALUES(prijato),
xml_soubor = COALESCE(VALUES(xml_soubor), xml_soubor),
stazeno = CURRENT_TIMESTAMP
""", zprava_row)
zprava_id = _najdi_id(cur, "zprava", "id_zpravy", zprava["id_zpravy"])
# ── predpisy + jejich slozky ───────────────────────────────────────────
vlozeno_p = 0
vlozeno_ps = 0
for row, slozky in predpisy:
row["zprava_id"] = zprava_id
cur.execute("""
INSERT IGNORE INTO predpis
(zprava_id, id_lp_predpis, kod_predepisujiciho,
datum_vystaveni, mnozstvi, navod, opakovani, modry_pruh,
typ_leku, lek_kod, atc, nazev, forma, sila,
cesta_podani, baleni, postup_pripravy)
VALUES
(%(zprava_id)s, %(id_lp_predpis)s, %(kod_predepisujiciho)s,
%(datum_vystaveni)s, %(mnozstvi)s, %(navod)s,
%(opakovani)s, %(modry_pruh)s,
%(typ_leku)s, %(lek_kod)s, %(atc)s, %(nazev)s, %(forma)s,
%(sila)s, %(cesta_podani)s, %(baleni)s, %(postup_pripravy)s)
""", row)
vlozeno_p += cur.rowcount
if slozky:
iplp_predpisu += 1
predpis_db_id = cur.lastrowid or _najdi_id(cur, "predpis", "id_lp_predpis", row["id_lp_predpis"])
for s in slozky:
s["predpis_id"] = predpis_db_id
cur.execute("""
INSERT INTO predpis_slozka
(predpis_id, mnozstvi, jednotka, nazev, surovina, hvlp_reg)
VALUES
(%(predpis_id)s, %(mnozstvi)s, %(jednotka)s,
%(nazev)s, %(surovina)s, %(hvlp_reg)s)
""", s)
vlozeno_ps += 1
# ── vydeji + jejich slozky ────────────────────────────────────────────
vlozeno_v = 0
vlozeno_vs = 0
for row, slozky in vydeji:
row["zprava_id"] = zprava_id
cur.execute("""
INSERT IGNORE INTO vydej
(zprava_id, id_lp_vydej, id_lp_predpis, kod_vydavajiciho,
datum_vydeje, mnozstvi, navod, exspirace, sarze,
seriove_cislo, pozn,
typ_leku, lek_kod, atc, nazev, forma, sila,
cesta_podani, postup_pripravy)
VALUES
(%(zprava_id)s, %(id_lp_vydej)s, %(id_lp_predpis)s, %(kod_vydavajiciho)s,
%(datum_vydeje)s, %(mnozstvi)s, %(navod)s, %(exspirace)s, %(sarze)s,
%(seriove_cislo)s, %(pozn)s,
%(typ_leku)s, %(lek_kod)s, %(atc)s, %(nazev)s, %(forma)s,
%(sila)s, %(cesta_podani)s, %(postup_pripravy)s)
""", row)
vlozeno_v += cur.rowcount
if slozky:
iplp_vydejuu += 1
vydej_db_id = cur.lastrowid or _najdi_id(cur, "vydej", "id_lp_vydej", row["id_lp_vydej"])
for s in slozky:
s["vydej_id"] = vydej_db_id
cur.execute("""
INSERT INTO vydej_slozka
(vydej_id, mnozstvi, jednotka, nazev,
hrazeno_zp, surovina, hvlp_reg)
VALUES
(%(vydej_id)s, %(mnozstvi)s, %(jednotka)s, %(nazev)s,
%(hrazeno_zp)s, %(surovina)s, %(hvlp_reg)s)
""", s)
vlozeno_vs += 1
# ── predepisujici ─────────────────────────────────────────────────────
for row in predepisujici:
if not row.get("lekar_kod"):
continue
cur.execute("""
INSERT INTO predepisujici
(lekar_kod, prijmeni, jmena, icz, icp,
pzs_nazev, ulice, mesto, psc, telefon)
VALUES
(%(lekar_kod)s, %(prijmeni)s, %(jmena)s, %(icz)s, %(icp)s,
%(pzs_nazev)s, %(ulice)s, %(mesto)s, %(psc)s, %(telefon)s)
ON DUPLICATE KEY UPDATE
prijmeni = VALUES(prijmeni),
jmena = VALUES(jmena),
icz = VALUES(icz),
icp = VALUES(icp),
pzs_nazev = VALUES(pzs_nazev),
ulice = VALUES(ulice),
mesto = VALUES(mesto),
psc = VALUES(psc),
telefon = VALUES(telefon)
""", row)
# ── vydavajici ────────────────────────────────────────────────────────
for row in vydavajici:
if not row.get("lekarnik_kod"):
continue
cur.execute("""
INSERT INTO vydavajici
(lekarnik_kod, prijmeni, jmena,
pzs_nazev, ulice, mesto, psc, telefon)
VALUES
(%(lekarnik_kod)s, %(prijmeni)s, %(jmena)s,
%(pzs_nazev)s, %(ulice)s, %(mesto)s, %(psc)s, %(telefon)s)
ON DUPLICATE KEY UPDATE
prijmeni = VALUES(prijmeni),
jmena = VALUES(jmena),
pzs_nazev = VALUES(pzs_nazev),
ulice = VALUES(ulice),
mesto = VALUES(mesto),
psc = VALUES(psc),
telefon = VALUES(telefon)
""", row)
conn.commit()
return dict(
predpisy_novych = vlozeno_p,
predpisy_celkem = len(predpisy),
vydeji_novych = vlozeno_v,
vydeji_celkem = len(vydeji),
predpis_slozka = vlozeno_ps,
vydej_slozka = vlozeno_vs,
)
# ── main ──────────────────────────────────────────────────────────────────────
def main():
xml = Path(sys.argv[1]) if len(sys.argv) > 1 else XML_SOUBOR
print(f"XML: {xml} ({xml.stat().st_size // 1024} KB)")
print("Parsovani XML ...")
zprava, predpisy, vydeji, predepisujici, vydavajici = parsuj_xml(xml)
print(f" -> {len(predpisy)} predpisu, {len(vydeji)} vydejuu, "
f"{len(predepisujici)} predepisujicich, {len(vydavajici)} vydavajicich")
print("Pripojeni k MySQL ...")
conn = pymysql.connect(**DB)
try:
vytvor_schema(conn)
print("Ukladani ...")
stats = uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici)
print(f" predpisy: {stats['predpisy_novych']} novych (celkem {stats['predpisy_celkem']})")
print(f" vydeji: {stats['vydeji_novych']} novych (celkem {stats['vydeji_celkem']})")
print(f" slozky: {stats['predpis_slozka']} predpis / {stats['vydej_slozka']} vydej")
print("Hotovo OK")
finally:
conn.close()
if __name__ == "__main__":
main()
@@ -0,0 +1,427 @@
"""
Hromadne stazeni lekovych zaznamu z eReceptu pro registrovane pacienty Medicusu.
Spusteni:
# pouze rodina (testovaci run)
python 07StahnoutVsechny.py --prijmeni Buzalka,Buzalkova,Kusinova
# vsichni registrovani pacienti
python 07StahnoutVsechny.py
# davkovani po castech
python 07StahnoutVsechny.py --offset 100 --limit 50
Vystup:
Konzole — jeden stručny radek na pacienta
Logs/ — kompletni log se vsemi detaily (UTF-8)
Logika poctu mesicu:
- prvni stazeni pacienta → 60 mesicu (maximum)
- opakovane stazeni → ceil(pocet_dni_od_posledniho / 30) + 1
(prekryv 1 mesic pro jistotu, INSERT IGNORE zajisti bez duplikatu)
XML archiv:
xml_archive/YYYY-MM-DD/{Prijmeni}_{Jmena}_{datnar}.xml
Cesta ulozena take v zprava.xml_soubor pro snadne dohledani.
"""
import argparse
import importlib.util
import logging
import math
import random
import sys
import time
import uuid
from datetime import datetime, timezone, date
from pathlib import Path
from xml.sax.saxutils import escape as xml_escape
import fdb
import pymysql
import pymysql.cursors
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
# Windows konzole — nahrad neunikatni znaky misto padu
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(errors="replace")
# ── Import parsovaci logiky z 06 ──────────────────────────────────────────────
_spec = importlib.util.spec_from_file_location(
"m06", Path(__file__).parent / "06UlozitDoMySQL.py"
)
_m06 = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_m06)
parsuj_xml = _m06.parsuj_xml
uloz = _m06.uloz
inicializuj_schema = _m06.inicializuj_schema
# ── Konfigurace eRecept ───────────────────────────────────────────────────────
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASS = "Vlado7309208104++"
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINT = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar2"
POCET_ZNAKU_ATC = 7
POCET_MESICU_MAX = 60
PAUZA_MIN = 10 # sekund
PAUZA_MAX = 20 # sekund
# ── Konfigurace Firebird ──────────────────────────────────────────────────────
FB_DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
FB_USER = 'SYSDBA'
FB_PASS = 'masterkey'
FB_CHARSET = 'win1250'
ICP = '09305001'
ODB = '001'
# ── Konfigurace MySQL ─────────────────────────────────────────────────────────
DB = dict(
host = "192.168.1.76",
user = "root",
password = "Vlado9674+",
database = "medicus",
charset = "utf8mb4",
cursorclass = pymysql.cursors.DictCursor,
)
# ── Adresare ──────────────────────────────────────────────────────────────────
XML_DIR = Path(__file__).parent / "xml_archive"
LOGS_DIR = Path(__file__).parent / "Logs"
# ── Logging ───────────────────────────────────────────────────────────────────
def setup_logging(dnes_str, cas_str):
"""
Dva handlery:
- soubor (DEBUG) → Logs/YYYY-MM-DD_HH-MM-SS.log — vse vcetne detailu
- konzole (INFO) → stdout — jen souhrnne radky
"""
LOGS_DIR.mkdir(exist_ok=True)
log_soubor = LOGS_DIR / f"{dnes_str}_{cas_str}.log"
log = logging.getLogger("lz")
log.setLevel(logging.DEBUG)
fh = logging.FileHandler(log_soubor, encoding="utf-8")
fh.setLevel(logging.DEBUG)
fh.setFormatter(logging.Formatter("%(asctime)s %(message)s", datefmt="%H:%M:%S"))
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.INFO)
ch.setFormatter(logging.Formatter("%(message)s"))
log.addHandler(fh)
log.addHandler(ch)
return log, log_soubor
# ── Firebird: nacteni registrovanych pacientu ─────────────────────────────────
_SQL_VSICHNI = """
SELECT
KAR.IDPAC,
KAR.PRIJMENI,
KAR.JMENO,
KAR.DATNAR
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 = ?)
AND (i.odb = ?)
)
ORDER BY KAR.PRIJMENI_UP, KAR.RODCIS
"""
_SQL_FILTR = """
SELECT
KAR.IDPAC,
KAR.PRIJMENI,
KAR.JMENO,
KAR.DATNAR
FROM KAR
WHERE (vyrazen = 'N')
AND KAR.PRIJMENI IN ({ph})
ORDER BY KAR.PRIJMENI_UP, KAR.RODCIS
"""
def nacti_pacienty(prijmeni_filtr=None):
conn = fdb.connect(dsn=FB_DSN, user=FB_USER, password=FB_PASS, charset=FB_CHARSET)
try:
cur = conn.cursor()
if prijmeni_filtr:
ph = ",".join("?" * len(prijmeni_filtr))
cur.execute(_SQL_FILTR.format(ph=ph), prijmeni_filtr)
else:
dnes = date.today().isoformat()
cur.execute(_SQL_VSICHNI, (dnes, dnes, ICP, ODB))
cols = [d[0].lower() for d in cur.description]
return [dict(zip(cols, row)) for row in cur.fetchall()]
finally:
conn.close()
# ── MySQL: pacient UPSERT ─────────────────────────────────────────────────────
def upsert_pacient(cur, pac):
cur.execute("""
INSERT INTO pacient (idpac, prijmeni, jmena, datum_narozeni)
VALUES (%s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
prijmeni = VALUES(prijmeni),
jmena = VALUES(jmena)
""", (pac["idpac"], pac["prijmeni"], pac["jmeno"], pac["datnar"]))
cur.execute("SELECT id FROM pacient WHERE idpac = %s", (pac["idpac"],))
return cur.fetchone()["id"]
def posledni_stazeni(cur, pacient_id):
cur.execute(
"SELECT MAX(stazeno) AS posledni FROM zprava WHERE pacient_id = %s",
(pacient_id,)
)
row = cur.fetchone()
return row["posledni"] if row and row["posledni"] else None
def vypocti_pocet_mesicu(posledni):
if posledni is None:
return POCET_MESICU_MAX
delta_dni = (datetime.now() - posledni).days
return min(math.ceil(delta_dni / 30) + 1, POCET_MESICU_MAX)
def uloz_poznamku(conn, pacient_id, poznamka):
with conn.cursor() as cur:
cur.execute(
"UPDATE pacient SET poznamka = %s WHERE id = %s",
(poznamka, pacient_id)
)
conn.commit()
# ── SOAP volani ───────────────────────────────────────────────────────────────
def extrahuj_soap_fault(xml_text):
"""Vraci text chyby pokud odpoved obsahuje SOAP Fault, jinak None."""
try:
import xml.etree.ElementTree as ET
NS_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
NS_SUKL = "http://www.sukl.cz/erp/201912"
root = ET.fromstring(xml_text)
body = root.find(f"{{{NS_SOAP}}}Body")
if body is None:
return "Chybejici SOAP Body"
fault = body.find(f"{{{NS_SOAP}}}Fault") or body.find("Fault")
if fault is not None:
faultstring = (fault.findtext("faultstring")
or fault.findtext("faultcode")
or "Nezname SOAP Fault")
detail = fault.find("detail")
if detail is not None and detail.text:
faultstring = f"{faultstring}: {detail.text.strip()[:200]}"
return faultstring
if body.find(f"{{{NS_SUKL}}}NacistLekovyZaznamOdpoved") is None:
first = list(body)
tag = first[0].tag if first else "prazdne Body"
return f"Neocekavana odpoved: {tag}"
return None
except Exception as e:
return f"Chyba pri parsovani odpovedi: {e}"
def nacti_lekovy_zaznam(sess, prijmeni, jmena, datum_narozeni, pocet_mesicu):
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
soap = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
f'<NacistLekovyZaznamLekarDotaz xmlns="http://www.sukl.cz/erp/201912">'
f'<Doklad>'
f'<Pristupujici>'
f'<Uzivatel>{UZIVATEL}</Uzivatel>'
f'<Pracoviste>{PRACOVISTE}</Pracoviste>'
f'</Pristupujici>'
f'<PocetZnakuATC>{POCET_ZNAKU_ATC}</PocetZnakuATC>'
f'<PocetMesicu>{pocet_mesicu}</PocetMesicu>'
f'<Pacient><Totoznost><Jmeno>'
f'<Prijmeni>{xml_escape(prijmeni)}</Prijmeni>'
f'<Jmena>{xml_escape(jmena)}</Jmena>'
f'</Jmeno><DatumNarozeni>{datum_narozeni}</DatumNarozeni>'
f'</Totoznost></Pacient>'
f'</Doklad>'
f'<Zprava>'
f'<ID_Zpravy>{id_zpravy}</ID_Zpravy>'
f'<Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano>'
f'<SW_Klienta>MEDICUS_____</SW_Klienta>'
f'</Zprava>'
f'</NacistLekovyZaznamLekarDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"',
"User-Agent": "Medicus",
}
resp = sess.post(ENDPOINT, data=soap.encode("utf-8"), headers=headers, timeout=60)
if resp.status_code != 200:
raise RuntimeError(f"HTTP {resp.status_code}: {resp.text[:300]}")
return resp.text
# ── XML archiv ────────────────────────────────────────────────────────────────
def uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str):
adr = XML_DIR / dnes_str
adr.mkdir(parents=True, exist_ok=True)
nazev = f"{prijmeni}_{jmena}_{datnar_str}.xml".replace(" ", "_")
soubor = adr / nazev
soubor.write_text(xml_text, encoding="utf-8")
return str(soubor.relative_to(Path(__file__).parent))
# ── Hlavni smycka ─────────────────────────────────────────────────────────────
def main():
ap = argparse.ArgumentParser(description="Hromadne stazeni lekovych zaznamu z eReceptu")
ap.add_argument("--prijmeni", default=None,
help="Filtr prijmeni oddelena carkou, napr: Buzalka,Buzalkova,Kusinova")
ap.add_argument("--limit", type=int, default=None, help="Zpracuj pouze N pacientu")
ap.add_argument("--offset", type=int, default=0,
help="Preskoc prvnich N pacientu (pro postupne davkovani)")
args = ap.parse_args()
dnes_str = date.today().isoformat()
cas_str = datetime.now().strftime("%H-%M-%S")
log, log_soubor = setup_logging(dnes_str, cas_str)
prijmeni_filtr = None
if args.prijmeni:
prijmeni_filtr = [p.strip() for p in args.prijmeni.split(",")]
log.info(f"Filtr prijmeni: {prijmeni_filtr}")
log.info("Nacitam pacienty z Medicusu...")
pacienti = nacti_pacienty(prijmeni_filtr)
log.debug(f"Celkem registrovanych: {len(pacienti)}")
if args.offset:
pacienti = pacienti[args.offset:]
log.debug(f"Preskoceno: {args.offset}")
if args.limit:
pacienti = pacienti[:args.limit]
log.debug(f"Omezeno na: {len(pacienti)}")
celkem = len(pacienti)
log.info(f"Pacientu ke zpracovani: {celkem} | log: {log_soubor.name}")
if not celkem:
log.info("Zadni pacienti — konec.")
return
conn = pymysql.connect(**DB)
inicializuj_schema(conn)
log.debug("MySQL schema OK")
sess = Session()
sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASS))
sess.auth = (API_USER, API_PASS)
ok = 0
chyby = 0
try:
for i, pac in enumerate(pacienti, 1):
prijmeni = pac["prijmeni"]
jmena = pac["jmeno"]
datnar = pac["datnar"]
datnar_str = datnar.isoformat() if hasattr(datnar, "isoformat") else str(datnar)
jmeno_str = f"{prijmeni} {jmena}"
log.debug(f"[{i:4}/{celkem}] {jmeno_str} (*{datnar_str})")
with conn.cursor() as cur:
pacient_id = upsert_pacient(cur, pac)
posledni = posledni_stazeni(cur, pacient_id)
conn.commit()
pocet_mesicu = vypocti_pocet_mesicu(posledni)
log.debug(f" stahuju {pocet_mesicu}m "
f"(posledni: {posledni.strftime('%Y-%m-%d') if posledni else 'nikdy'})")
# Zavolej API
try:
xml_text = nacti_lekovy_zaznam(sess, prijmeni, jmena, datnar_str, pocet_mesicu)
except Exception as e:
zprava_chyby = str(e)[:400]
log.debug(f" CHYBA API: {zprava_chyby}")
log.info(f"[{i:4}/{celkem}] {jmeno_str:<30} CHYBA {zprava_chyby[:60]}")
uloz_poznamku(conn, pacient_id, zprava_chyby)
chyby += 1
continue
# Detekuj SOAP Fault
soap_fault = extrahuj_soap_fault(xml_text)
if soap_fault:
log.debug(f" SOAP FAULT: {soap_fault}")
log.info(f"[{i:4}/{celkem}] {jmeno_str:<30} CHYBA {soap_fault[:60]}")
uloz_poznamku(conn, pacient_id, soap_fault[:400])
chyby += 1
continue
# Uloz XML
xml_soubor = uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str)
xml_path = Path(__file__).parent / xml_soubor
kb = xml_path.stat().st_size // 1024
log.debug(f" XML: {xml_soubor} ({kb} KB)")
# Parsuj + uloz do MySQL
try:
zprava_d, predpisy, vydeji, predepisujici, vydavajici = parsuj_xml(xml_path)
stats = uloz(conn, zprava_d, predpisy, vydeji, predepisujici, vydavajici,
pacient_id=pacient_id, xml_soubor=xml_soubor)
uloz_poznamku(conn, pacient_id, None)
log.debug(f" predpisy: {stats['predpisy_novych']}n/{stats['predpisy_celkem']} "
f"vydeji: {stats['vydeji_novych']}n/{stats['vydeji_celkem']} "
f"slozky: {stats['predpis_slozka']}p/{stats['vydej_slozka']}v")
log.info(f"[{i:4}/{celkem}] {jmeno_str:<30} OK "
f"{stats['predpisy_celkem']:4}p {stats['vydeji_celkem']:4}v {kb:4} KB")
ok += 1
except Exception as e:
zprava_chyby = str(e)[:400]
log.debug(f" CHYBA parsovani/ulozeni: {zprava_chyby}")
log.info(f"[{i:4}/{celkem}] {jmeno_str:<30} CHYBA {zprava_chyby[:60]}")
uloz_poznamku(conn, pacient_id, zprava_chyby)
chyby += 1
if i < celkem:
pauza = random.randint(PAUZA_MIN, PAUZA_MAX)
log.debug(f" cekam {pauza}s ...")
time.sleep(pauza)
finally:
conn.close()
sess.close()
zhrnutí = f"Hotovo: {ok} OK | {chyby} chyb | celkem {celkem} pacientu"
log.info("=" * 55)
log.info(zhrnutí)
if __name__ == "__main__":
main()
@@ -0,0 +1,543 @@
# Lékový záznam eRecept → MySQL
Pipeline pro hromadné stažení lékových záznamů všech registrovaných pacientů
z eRecept SÚKL API a jejich uložení do relační databáze MySQL.
---
## Soubory
| Soubor | Co dělá |
|--------|---------|
| `05UlozitOdpoved.py` | Stáhne XML pro **jednoho** pacienta (ruční test/ladění) |
| `06UlozitDoMySQL.py` | DDL schématu, parsování XML, import do MySQL — používá se jako **knihovna**, ne spouštět přímo! |
| `07StahnoutVsechny.py` | **Hlavní skript** — načte pacienty z Medicusu, stáhne lékové záznamy, uloží XML i DB záznamy |
| `reimport_z_xml.py` | Reimport XML ze zálohy bez volání API — viz sekce níže |
```
recept/
├── setup.ps1 ← vytvoří .venv, nainstaluje závislosti, Playwright chromium
├── requirements.txt ← seznam Python závislostí
├── .venv/ ← virtuální prostředí (Python 3.x)
├── LékovýZáznamWithClaude/
│ ├── 05UlozitOdpoved.py
│ ├── 06UlozitDoMySQL.py
│ ├── 07StahnoutVsechny.py
│ ├── reimport_z_xml.py
│ ├── LEKOVY_ZAZNAM_DB.md ← tento soubor
│ ├── Logs/ ← log každého běhu (UTF-8, YYYY-MM-DD_HH-MM-SS.log)
│ ├── Tests/ ← starší vývojové skripty
│ └── xml_archive/ ← archiv XML odpovědí (YYYY-MM-DD/Prijmeni_Jmena_datnar.xml)
└── Dotazy/
├── prehled_pacienta.py ← konzolový přehled pacienta
├── prehled_pacienta_excel.py ← export přehledu pacienta do Excelu
└── DOTAZY.md ← dokumentace dotazovacích skriptů
```
> **⚠️ NIKDY nespouštět `06UlozitDoMySQL.py` přímo** — zavolá `vytvor_schema()`,
> která provede `DROP TABLE` a smaže celou databázi.
> Pro import dat vždy použít `07StahnoutVsechny.py` nebo `reimport_z_xml.py`.
---
## Nastavení prostředí (jednorázově)
```powershell
# PowerShell — spustit jednou po naklonování projektu
cd U:\recept
.\setup.ps1
```
`setup.ps1` provede:
1. Vytvoří `.venv` s Python interpretem z `C:\Python\python.exe`
2. Nainstaluje všechny závislosti z `requirements.txt`
3. Nainstaluje Playwright Chromium (pro případné automatizace)
Po nastavení aktivace:
```powershell
.venv\Scripts\Activate.ps1
```
### requirements.txt
```
requests
requests-pkcs12
pymysql
fdb
zeep
mysql-connector-python
playwright
openpyxl
```
---
## Typické spuštění
```bash
# Hromadné stažení všech registrovaných pacientů
python 07StahnoutVsechny.py
# Pouze vybraná příjmení (testování / rodina)
python 07StahnoutVsechny.py --prijmeni Buzalka,Buzalková,Kusinová
# Dávkování po částech
python 07StahnoutVsechny.py --offset 100 --limit 50
# Reimport ze zálohy XML (bez volání API) — viz níže
python reimport_z_xml.py
```
---
## 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**.
---
## Zdroj pacientů — Medicus (Firebird)
Pacienti se načítají přímo z `medicus.fdb` jako registrovaní pacienti ordinace:
```
DSN: localhost:c:\medicus 3\data\medicus.fdb
User: SYSDBA / masterkey
Charset: win1250
IČP: 09305001 (odbornost 001 — praktický lékař)
```
Podmínky registrace: `vyrazen = 'N'`, `registr.priznak IN ('V','D','A')`,
registrace platná k dnešnímu datu.
---
## Logika přírůstkového stahování
```
první stažení pacienta → PocetMesicu = 60 (maximum, 5 let)
opakované stažení → ceil(dny od posledního stažení / 30) + 1
```
- Překryv 1 měsíce zajistí, že nepřijdeme o nic na hranici období.
- `INSERT IGNORE` na `id_lp_predpis` / `id_lp_vydej` zabrání duplikátům.
- Pauza mezi voláními API: **náhodně 1020 sekund**.
---
## Ošetření chyb API
Pacienti, kteří nejsou v eReceptu ztotožněni (nikdy nebyli v lékárně s e-receptem),
vrátí SOAP Fault `Z002`. Skript:
1. Zachytí chybu (HTTP 500 nebo SOAP Fault v těle odpovědi)
2. Uloží text chyby do `pacient.poznamka`
3. Pokračuje dalším pacientem
Při příštím úspěšném stažení se `poznamka` automaticky vymaže.
```sql
-- přehled pacientů s chybou
SELECT prijmeni, jmena, datum_narozeni, poznamka
FROM pacient
WHERE poznamka IS NOT NULL;
```
---
## XML archiv
Každá odpověď API se uloží jako soubor:
```
xml_archive/YYYY-MM-DD/Prijmeni_Jmena_YYYY-MM-DD.xml
```
Cesta je zároveň uložena v `zprava.xml_soubor`.
Účel: možnost re-parsování při budoucích změnách schématu bez nutnosti znovu volat API.
---
## Výstup do konzole a logů
Konzole zobrazuje jen jeden řádek na pacienta:
```
[ 1/1621] Abohamda Horia OK 168p 252v 247 KB
[ 5/1621] Alakbarov Farid CHYBA Z002 - Lekovy zaznam ne...
```
Kompletní detaily (počty nových záznamů, ID zprávy, doba čekání) jsou v:
```
Logs/YYYY-MM-DD_HH-MM-SS.log
```
---
## Databázové schéma — `medicus` (MySQL)
Všechny délky a datové typy jsou přesně dle XSD, **ne odhady**.
Lék je denormalizován přímo do řádku předpisu/výdeje.
### Relační diagram
```
pacient (1)
└── zprava (N) -- každé volání API = 1 zpráva
├── 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)
predpis.kod_predepisujiciho → predepisujici.lekar_kod
vydej.kod_vydavajiciho → vydavajici.lekarnik_kod
```
### Tabulka `pacient`
Zrcadlo registrovaných pacientů z Medicusu. Aktualizuje se při každém běhu `07`.
| Sloupec | Typ | Poznámka |
|---------|-----|----------|
| `id` | INT PK | |
| `idpac` | INT UNIQUE | IDPAC z tabulky KAR v Medicusu |
| `prijmeni` | VARCHAR(35) | |
| `jmena` | VARCHAR(24) | |
| `datum_narozeni` | DATE | |
| `aktivni` | TINYINT(1) | 0 = přeskočit při hromadném běhu |
| `poznamka` | VARCHAR(500) | poslední chyba API; NULL = OK |
### Tabulka `zprava`
Jeden řádek = jedno volání API (jeden pacient, jeden čas).
| Sloupec | Typ | Poznámka |
|---------|-----|----------|
| `id_zpravy` | CHAR(36) UNIQUE | UUID z eReceptu |
| `pacient_id` | INT FK → pacient | |
| `verze` | VARCHAR(20) | verze zprávy (202501A) |
| `odeslano` | DATETIME | čas odeslání dotazu |
| `aplikace` | VARCHAR(512) | SW SÚKL serveru |
| `id_podani` | CHAR(36) | UUID podání |
| `prijato` | DATETIME | čas přijetí odpovědi |
| `pacient_prijmeni` | VARCHAR(35) | z XML odpovědi |
| `pacient_jmena` | VARCHAR(24) | z XML odpovědi |
| `pacient_datum_narozeni` | DATE | z XML odpovědi |
| `xml_soubor` | VARCHAR(255) | relativní cesta k archivu |
| `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) UNIQUE | ✓ | UUID z eReceptu |
| `zprava_id` | INT FK | ✓ | |
| `kod_predepisujiciho` | VARCHAR(36) | ✓ | UUID lékaře |
| `datum_vystaveni` | DATE | ✓ | |
| `mnozstvi` | SMALLINT | ✓ | 19999 |
| `navod` | VARCHAR(80) | ✓ | |
| `opakovani` | INT | | |
| `modry_pruh` | TINYINT(1) | | 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 |
| `nazev` | VARCHAR(200) | | |
| `forma` | VARCHAR(27) | | |
| `sila` | VARCHAR(24) | | |
| `cesta_podani` | VARCHAR(15) | | POR, INH, … |
| `baleni` | VARCHAR(22) | | string, např. "100 ks" |
| `postup_pripravy` | VARCHAR(4000) | | receptura IPLP |
### Tabulka `predpis_slozka`
Složky IPLP předpisů (lékař typicky nevyplňuje, kvalitní data spíše u výdeje).
| Sloupec | Typ | NOT NULL |
|---------|-----|----------|
| `predpis_id` | INT FK | ✓ |
| `mnozstvi` | DECIMAL(15,6) | ✓ |
| `jednotka` | ENUM('g','ks') | ✓ |
| `nazev` | VARCHAR(200) | ✓ |
| `surovina` | CHAR(7) | |
| `hvlp_reg` | CHAR(7) | |
### Tabulka `vydej`
Dle `lz_nacteni_vydany_lp_erp_type`.
| Sloupec | Typ | NOT NULL | Poznámka |
|---------|-----|----------|----------|
| `id_lp_vydej` | CHAR(36) UNIQUE | ✓ | UUID výdeje |
| `zprava_id` | INT FK | ✓ | |
| `id_lp_predpis` | CHAR(36) FK | | 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) | ✓ | |
| `seriove_cislo` | VARCHAR(20) | | 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 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`
Jako `predpis_slozka`, navíc `hrazeno_zp`. Data lékáren — kvalita závisí na lékárně.
| Sloupec | Typ | NOT NULL | Poznámka |
|---------|-----|----------|----------|
| `vydej_id` | INT FK | ✓ | |
| `mnozstvi` | DECIMAL(15,6) | ✓ | |
| `jednotka` | ENUM('g','ks') | ✓ | |
| `nazev` | VARCHAR(200) | ✓ | |
| `hrazeno_zp` | DECIMAL(9,2) | | částka hrazená ZP |
| `surovina` | CHAR(7) | | |
| `hvlp_reg` | CHAR(7) | | |
### Tabulka `predepisujici`
Lékaři, kteří pacientovi předepisovali (ze všech ordinací).
| Sloupec | Typ | Poznámka |
|---------|-----|----------|
| `lekar_kod` | CHAR(36) UNIQUE | UUID lékaře = predpis.kod_predepisujiciho |
| `prijmeni` | VARCHAR(35) | |
| `jmena` | VARCHAR(24) | |
| `icz` | CHAR(8) | IČZ zdravotnického zařízení |
| `icp` | CHAR(8) | IČP pracoviště — **poslední 3 číslice = kód odbornosti** (001 = prakt. lékař, 272 = alergologie…) |
| `pzs_nazev` | VARCHAR(200) | název zdravotnického zařízení |
| `ulice` | VARCHAR(150) | |
| `mesto` | VARCHAR(100) | |
| `psc` | CHAR(5) | |
| `telefon` | VARCHAR(20) | |
### Tabulka `vydavajici`
Lékárníci / lékárny, kde byl výdej.
| Sloupec | Typ | Poznámka |
|---------|-----|----------|
| `lekarnik_kod` | CHAR(36) UNIQUE | UUID lékárníka = vydej.kod_vydavajiciho |
| `prijmeni` | VARCHAR(35) | |
| `jmena` | VARCHAR(24) | |
| `pzs_nazev` | VARCHAR(200) | název lékárny |
| `ulice` | VARCHAR(150) | |
| `mesto` | VARCHAR(100) | |
| `psc` | CHAR(5) | |
| `telefon` | VARCHAR(20) | |
---
## 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, Slozka[] |
| `INN` | Předpis účinnou látkou (genericky) | Nazev, Forma, Sila, Baleni |
#### IPLP — dvojí uložení receptury
- **Předpis**: lékař zadal recepturu jako volný text v `PostupPripravy`. Složky typicky nevyplněny.
- **Výdej**: lékárna zaznamenala strukturované složky (`Slozka` s množstvím, jednotkou, názvem suroviny). Kvalita dat závisí na lékárně.
---
## Užitečné analytické dotazy
```sql
-- 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 (non-compliance)
SELECT pac.prijmeni, pac.jmena, p.datum_vystaveni, p.nazev, p.atc, p.navod
FROM predpis p
JOIN zprava z ON z.id = p.zprava_id
JOIN pacient pac ON pac.id = z.pacient_id
LEFT JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis
WHERE v.id_lp_vydej IS NULL
ORDER BY p.datum_vystaveni DESC;
-- lékový záznam konkrétního pacienta (předpisy + výdeje)
SELECT p.datum_vystaveni, p.typ_leku, p.nazev, p.atc, p.navod,
v.datum_vydeje, v.mnozstvi AS vydano
FROM pacient pac
JOIN zprava z ON z.pacient_id = pac.id
JOIN predpis p ON p.zprava_id = z.id
LEFT JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis
WHERE pac.prijmeni = 'Buzalka' AND pac.jmena = 'Vladimír'
ORDER BY p.datum_vystaveni DESC;
-- IPLP magistraliter — kompletní receptury s frekvencí (napříč pacienty)
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;
-- nejčastěji používané suroviny v magistrech
SELECT nazev, jednotka, COUNT(*) AS pocet
FROM vydej_slozka
GROUP BY nazev, jednotka
ORDER BY pocet DESC;
-- generická záměna: co předepsal lékař vs. co lékárna vydala
SELECT pac.prijmeni, pac.jmena,
p.datum_vystaveni, p.nazev AS predepsano, p.atc,
v.nazev AS vydano, v.datum_vydeje
FROM pacient pac
JOIN zprava z ON z.pacient_id = pac.id
JOIN predpis p ON p.zprava_id = z.id
JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis
WHERE p.nazev <> v.nazev;
-- pacienti s chybou API (neztotožněni)
SELECT prijmeni, jmena, datum_narozeni, poznamka
FROM pacient
WHERE poznamka IS NOT NULL
ORDER BY prijmeni;
-- lékaři dle odbornosti — kolik předpisů pochází od které speciality
SELECT RIGHT(pr.icp, 3) AS odb_kod, COUNT(*) AS pocet_predpisu
FROM predpis p
JOIN predepisujici pr ON pr.lekar_kod = p.kod_predepisujiciho
WHERE pr.icp IS NOT NULL
GROUP BY RIGHT(pr.icp, 3)
ORDER BY pocet_predpisu DESC;
-- lékový záznam pacienta dle rodného čísla (přes Firebird → MySQL)
-- krok 1: z Medicusu zjistit příjmení a datum narozeni pro RC 7309208104
-- krok 2:
SELECT pac.prijmeni, pac.jmena, pac.datum_narozeni,
p.datum_vystaveni,
COALESCE(v.nazev, p.nazev) AS vydany_lek,
v.nazev IS NULL AS nevyzvednuto,
p.atc, p.navod,
pr.prijmeni AS lekar, RIGHT(pr.icp, 3) AS odb_kod
FROM pacient pac
JOIN zprava z ON z.pacient_id = pac.id
JOIN predpis p ON p.zprava_id = z.id
JOIN predepisujici pr ON pr.lekar_kod = p.kod_predepisujiciho
LEFT JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis
WHERE pac.prijmeni = 'Buzalka' AND pac.datum_narozeni = '1973-09-20'
ORDER BY p.datum_vystaveni DESC;
```
---
## Reimport ze zálohy XML (`reimport_z_xml.py`)
Slouží k opětovnému naplnění MySQL databáze z lokálních XML souborů **bez volání eRecept API**.
Použití: obnova po neúmyslném smazání databáze, migrace na nový server, re-parsování při změně schématu.
### Jak funguje
1. Načte všechny registrované pacienty z Firebirdu (ICP `09305001`, odbornost `001`)
2. Pro každý XML soubor v archivu:
- Naparsuje XML (volá `parsuj_xml()` z `06UlozitDoMySQL.py`)
- Dohledá pacienta v Firebirdu dle příjmení + data narození z XML
- Pokud je registrovaný → `upsert` pacienta do MySQL (INSERT ON DUPLICATE KEY UPDATE)
- Zavolá `uloz()` — INSERT IGNORE, takže duplicity se ignorují
3. Výpis průběhu: `[ 1/1177] Buzalka_Vladimir_1973-09-20.xml OK 12p 18v`
### Spuštění
```bash
# Výchozí adresář: xml_archive/2026-04-11
python reimport_z_xml.py
# Konkrétní podadresář
python reimport_z_xml.py xml_archive/2026-04-11
# Celý archiv rekurzivně (všechna data)
python reimport_z_xml.py xml_archive
```
### Konfigurace v souboru
```python
XML_ADRESAR = Path(__file__).parent / "xml_archive" / "2026-04-11" # výchozí adresář
ICP = "09305001" # IČP ordinace pro filtr registrovaných pacientů
ODB = "001" # odbornost (001 = praktický lékař)
```
### Poznámky
- Pacienti, kteří nejsou v Firebirdu registrováni pod daným ICP/ODB, se přeskočí
(pokud ale existují v MySQL z předchozího importu, data se aktualizují)
- Firebird slouží jako autoritativní zdroj identit — `idpac` z KAR se propíše do MySQL `pacient.idpac`
- `INSERT IGNORE` zajistí idempotentnost — opakované spuštění nepřidá duplikáty
---
## Dotazovací skripty (`Dotazy/`)
Viz samostatnou dokumentaci: [`Dotazy/DOTAZY.md`](../Dotazy/DOTAZY.md)
Stručný přehled:
| Skript | Co dělá |
|--------|---------|
| `prehled_pacienta.py` | Konzolový výpis lékového záznamu pacienta (lékaři + předpisy) |
| `prehled_pacienta_excel.py` | Totéž, ale exportuje do formátovaného souboru Excel (.xlsx) |
Pacient se identifikuje **rodným číslem** (nastavení `RODNE_CISLO` v záhlaví skriptu).
Oba skripty zobrazují **vydaný lék** (ne předepsaný), **odbornost lékaře** a příznak `*NV` pro nevyzvednuto.
---
## Závislosti (Python)
```
requests
requests-pkcs12
pymysql
fdb
zeep
mysql-connector-python
playwright
openpyxl
```
```bash
# Instalace (nebo použít setup.ps1)
pip install requests requests-pkcs12 pymysql fdb openpyxl
```
---
## XSD zdroje
Schéma verze `202501A`, soubory v `Dokumentace/2025-04-24/WSDL_XSD/NEPRIORITNI_WEBOVE_SLUZBY/`:
| Soubor | Obsah |
|--------|-------|
| `Cuer2Schema.xsd` | `NacistLekovyZaznamOdpoved`, `lz_nacteni_predepsany_lp_erp_type`, `lz_nacteni_vydany_lp_erp_type`, `slozka_iplp_*` |
| `CuerSchema.xsd` | `hvlp_type`, `zprava_odpoved_type`, `zprava_type`, `jmeno_osoby_type`, `jednotka` |
@@ -0,0 +1,77 @@
import uuid
from datetime import datetime, timezone
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
# --- Konfigurace ---
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
# HTTP Basic Auth - UUID lékaře (jednoznačný v ČR) + osobní heslo
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINTS = [
"https://lekar-soap.erecept.sukl.cz/cuer/Lekar2",
]
# --- Pacient ---
PRIJMENI = "Buzalka"
JMENA = "Vladimír"
DATUM_NAROZENI = "1973-09-20"
POCET_ZNAKU_ATC = 7
POCET_MESICU = 60
def nacist_lekovy_zaznam():
sess = Session()
sess.mount("https://", Pkcs12Adapter(
pkcs12_filename=PFX_FILE,
pkcs12_password=PFX_PASSWORD
))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
f'<NacistLekovyZaznamLekarDotaz xmlns="http://www.sukl.cz/erp/201912">'
f'<Doklad>'
f'<Pristupujici><Uzivatel>{UZIVATEL}</Uzivatel><Pracoviste>{PRACOVISTE}</Pracoviste></Pristupujici>'
f'<PocetZnakuATC>{POCET_ZNAKU_ATC}</PocetZnakuATC>'
f'<PocetMesicu>{POCET_MESICU}</PocetMesicu>'
f'<Pacient><Totoznost><Jmeno><Prijmeni>{PRIJMENI}</Prijmeni><Jmena>{JMENA}</Jmena></Jmeno>'
f'<DatumNarozeni>{DATUM_NAROZENI}</DatumNarozeni></Totoznost></Pacient>'
f'</Doklad>'
f'<Zprava><ID_Zpravy>{id_zpravy}</ID_Zpravy><Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano><SW_Klienta>MEDICUS_____</SW_Klienta></Zprava>'
f'</NacistLekovyZaznamLekarDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"',
"User-Agent": "Medicus"
}
for url in ENDPOINTS:
print(f"\n--- POST: {url} ---")
try:
resp = sess.post(url, data=soap_body.encode("utf-8"), headers=headers, timeout=15)
print(f"HTTP {resp.status_code} | {len(resp.content)} bytů")
print(resp.text)
except Exception as e:
print(f"CHYBA: {e}")
if __name__ == "__main__":
nacist_lekovy_zaznam()
@@ -0,0 +1,99 @@
import uuid
from datetime import datetime, timezone, timedelta
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
# --- Konfigurace ---
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINT = "https://cuer-soap.erecept.sukl.cz/"
# --- Filtr ---
CP_PACIENTA = "7309208104" # rodné číslo pacienta (bez lomítka)
DATUM_OD = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d")
DATUM_DO = datetime.now().strftime("%Y-%m-%d")
LIMIT = 100
def seznam_predpisu():
sess = Session()
sess.mount("https://", Pkcs12Adapter(
pkcs12_filename=PFX_FILE,
pkcs12_password=PFX_PASSWORD
))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
filtr_pacient = ""
if CP_PACIENTA:
filtr_pacient = f"<CP_Pacienta>{CP_PACIENTA}</CP_Pacienta>"
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
'<SeznamPredpisuDotaz xmlns="http://www.sukl.cz/erp/201704">'
'<Doklad>'
f'<Pristupujici><Uzivatel>{UZIVATEL}</Uzivatel><Pracoviste>{PRACOVISTE}</Pracoviste></Pristupujici>'
f'<Filtr>'
f'<DatumOd>{DATUM_OD}</DatumOd>'
f'<DatumDo>{DATUM_DO}</DatumDo>'
f'<Limit>{LIMIT}</Limit>'
f'{filtr_pacient}'
f'</Filtr>'
'</Doklad>'
f'<Zprava>'
f'<ID_Zpravy>{id_zpravy}</ID_Zpravy>'
f'<Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano>'
f'<SW_Klienta>MEDICUS_____</SW_Klienta>'
f'</Zprava>'
'</SeznamPredpisuDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"SeznamPredpisu"',
"User-Agent": "Medicus"
}
print(f"=== SOAP REQUEST ===\n{soap_body}\n===================\n")
print(f"Datum od: {DATUM_OD}, do: {DATUM_DO}, limit: {LIMIT}")
if CP_PACIENTA:
print(f"Filtr pacienta (RC): {CP_PACIENTA}")
print(f"ID zprávy: {id_zpravy}")
print(f"Endpoint: {ENDPOINT}\n")
resp = sess.post(ENDPOINT, data=soap_body.encode("utf-8"), headers=headers, timeout=30)
print(f"HTTP status: {resp.status_code}")
output_file = f"seznam_predpisu_{id_zpravy}.xml"
with open(output_file, "wb") as f:
f.write(resp.content)
print(f"Odpověď uložena do: {output_file}")
text = resp.text
if "Fault" in text or "fault" in text:
print("\n!!! SOAP Fault v odpovědi !!!")
print(text[:2000])
else:
print("Dotaz proběhl úspěšně.")
print(f"Velikost odpovědi: {len(resp.content):,} bytů")
print("\n--- Odpověď (prvních 3000 znaků) ---")
print(text[:3000])
if __name__ == "__main__":
seznam_predpisu()
@@ -0,0 +1,66 @@
import uuid
from datetime import datetime, timezone
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
sess = Session()
sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASSWORD))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+01:00")
# Přesně tělo z Medicusu
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
'<NacistLekovyZaznamLekarDotaz xmlns="http://www.sukl.cz/erp/201912">'
'<Doklad><Pristupujici>'
'<Uzivatel>E08C89C6-2B1A-4EBA-8ED9-4E3E63618379</Uzivatel>'
'<Pracoviste>00214235367</Pracoviste>'
'</Pristupujici>'
'<PocetZnakuATC>7</PocetZnakuATC>'
'<PocetMesicu>60</PocetMesicu>'
'<Pacient><Totoznost><Jmeno>'
'<Prijmeni>Buzalka</Prijmeni>'
'<Jmena>Vladim\u00edr</Jmena>'
'</Jmeno>'
'<DatumNarozeni>1973-09-20</DatumNarozeni>'
'</Totoznost></Pacient></Doklad>'
f'<Zprava><ID_Zpravy>{id_zpravy}</ID_Zpravy>'
'<Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano>'
'<SW_Klienta>MEDICUS_____</SW_Klienta></Zprava>'
'</NacistLekovyZaznamLekarDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"',
"User-Agent": "Medicus"
}
endpoints = [
"https://cuer-soap.erecept.sukl.cz/",
"https://rlpo-soap.erecept.sukl.cz/",
"https://common-soap.erecept.sukl.cz/",
"https://lz-soap.erecept.sukl.cz/",
"https://lekar-soap.erecept.sukl.cz/cuer/Lekar",
]
for ep in endpoints:
print(f"\n--- {ep} ---")
try:
resp = sess.post(ep, data=soap_body.encode("utf-8"), headers=headers, timeout=10)
print(f"HTTP {resp.status_code} | {len(resp.content)} bytů")
print(resp.text[:300])
except Exception as e:
print(f"CHYBA: {e}")
@@ -0,0 +1,64 @@
import uuid
import xml.dom.minidom
from datetime import datetime, timezone
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
ENDPOINT = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar"
NAMESPACE = "http://www.sukl.cz/erp/201704"
def nacist_ciselnik_chyb():
sess = Session()
sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASSWORD))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
f'<CisChybDotaz xmlns="{NAMESPACE}">'
f'<Zprava>'
f'<ID_Zpravy>{id_zpravy}</ID_Zpravy>'
f'<Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano>'
f'<SW_Klienta>MEDICUS_____</SW_Klienta>'
f'</Zprava>'
f'</CisChybDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistCiselnikChyb"',
"User-Agent": "Medicus"
}
print(f"Volám: {ENDPOINT}")
resp = sess.post(ENDPOINT, data=soap_body.encode("utf-8"), headers=headers, timeout=15)
print(f"HTTP {resp.status_code} | {len(resp.content)} bytů\n")
if resp.status_code == 200:
# Hezky formátovaný výpis
dom = xml.dom.minidom.parseString(resp.content)
pretty = dom.toprettyxml(indent=" ", encoding="utf-8").decode("utf-8")
print(pretty)
# Uložit do souboru
fname = f"ciselnik_chyb_{id_zpravy[:8]}.xml"
with open(fname, "w", encoding="utf-8") as f:
f.write(pretty)
print(f"\nUloženo: {fname}")
else:
print(resp.text)
if __name__ == "__main__":
nacist_ciselnik_chyb()
@@ -0,0 +1,393 @@
# NacistLekovyZaznam — Funkční SOAP klient pro IS eRecept SÚKL
## Status
**OVĚŘENO FUNKČNÍ** — 5. dubna 2026
Odpověď serveru: `HTTP 200`, velikost: ~227 KB reálných dat
Schéma ověřeno proti: `Cuer2Schema.xsd` verze `202501A` (dokumentace SÚKL 2025-04-24)
---
## Co tato operace dělá
`NacistLekovyZaznam` je SOAP operace IS eRecept (SÚKL), která vrátí kompletní **lékový záznam pacienta** — tedy seznam všech předpisů a výdejů léků napříč všemi lékaři a lékárnami v ČR za zadané období.
Typické použití: lékař si před konzultací zobrazí, co pacient aktuálně bere, co mu bylo předepsáno a vydáno v lékárně.
---
## Klíčové informace (těžce dohledané)
### Endpoint (produkce)
```
https://lekar-soap.erecept.sukl.cz/cuer/Lekar2
```
> **Pozor:** Endpoint má na konci číslici `2` — tj. `/cuer/Lekar2`, nikoli `/cuer/Lekar`.
> Tato operace **není** dostupná na starším endpointu `/cuer/Lekar`.
> Poprvé zdokumentováno v: `eRecept_lekovy_zaznam_1v3.docx` (dokumentace SÚKL ze dne 2024-01-18).
### Endpoint (testovací prostředí)
```
https://lekar-soap.test-erecept.sukl.cz/cuer/Lekar2
```
### SOAPAction
```
"NacistLekovyZaznam"
```
### XML namespace
```
http://www.sukl.cz/erp/201912
```
> Namespace pochází z prosince 2019 a **nemění se** ani v novějších verzích rozhraní.
> Verze rozhraní se předává v elementu `<Verze>` uvnitř zprávy, ne změnou namespace.
> SÚKL zachovává zpětnou kompatibilitu — namespace zůstává `201912` i pro verze `202401A`, `202501A` atd.
---
## Další operace dostupné na stejném endpointu `/cuer/Lekar2`
Dle `CUERLekarService.wsdl` (2025-04-24) jsou na tomto endpointu celkem **4 operace**:
| Operace | SOAPAction | Popis |
|---|---|---|
| `NacistLekovyZaznam` | `NacistLekovyZaznam` | ✅ lékový záznam pacienta |
| `OverDuplicity` | `OverDuplicity` | kontrola duplicitních předpisů |
| `ZjistitPoznamkyHvlp` | `ZjistitPoznamkyHvlp` | poznámky k HVLP přípravkům |
| `GetAppInfo` | `GetAppInfo` | info o verzi API |
| `AppPing` | `AppPing` | test spojení |
---
## Autentizace (dvojitá)
IS eRecept vyžaduje **dvě vrstvy** autentizace současně:
### 1. Klientský certifikát (TLS mutual auth)
- Soubor: `AMBSUKL214235369G_31DEC2024.pfx` (certifikát lékaře vydaný SÚKL)
- Formát: PKCS#12 (`.pfx`)
- Knihovna: `requests-pkcs12``Pkcs12Adapter`
- Platnost certifikátu: do 31. 12. 2024 (při expiraci je nutné zažádat SÚKL o nový)
### 2. HTTP Basic Auth
- Uživatel: UUID lékaře (přiděluje SÚKL, jednoznačný v celé ČR)
- Heslo: osobní heslo lékaře do portálu eRecept
---
## Struktura SOAP dotazu
```xml
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NacistLekovyZaznamLekarDotaz xmlns="http://www.sukl.cz/erp/201912">
<Doklad>
<Pristupujici>
<Uzivatel>E08C89C6-2B1A-4EBA-8ED9-4E3E63618379</Uzivatel> <!-- UUID lékaře, povinný -->
<Pracoviste>00214235367</Pracoviste> <!-- IČP pracoviště, povinný -->
</Pristupujici>
<PocetZnakuATC>7</PocetZnakuATC> <!-- POUZE hodnoty 5 nebo 7 (enum!), povinný -->
<PocetMesicu>60</PocetMesicu> <!-- max 99, VOLITELNÝ -->
<Pacient>
<Totoznost>
<Jmeno>
<Prijmeni>Buzalka</Prijmeni>
<Jmena>Vladimír</Jmena>
</Jmeno>
<DatumNarozeni>1973-09-20</DatumNarozeni>
</Totoznost>
</Pacient>
<!-- Zastupce — volitelný, pouze pokud dotazuje zastupující lékař -->
<!-- <Zastupce>
<DruhDokladu>OP</DruhDokladu> 12 znaky, volitelný -->
<!-- <CisloDokladu>123456789</CisloDokladu> 19 znaků, volitelný -->
<!-- </Zastupce> -->
</Doklad>
<Zprava>
<ID_Zpravy>dabda2ad-df61-41db-bd46-a969eced026b</ID_Zpravy> <!-- UUID, generovat pro každý dotaz -->
<Verze>202501A</Verze> <!-- aktuální verze protokolu -->
<Odeslano>2026-04-05T10:00:00+00:00</Odeslano> <!-- UTC timestamp -->
<SW_Klienta>MEDICUS_____</SW_Klienta> <!-- identifikátor SW, přesně 12 znaků -->
</Zprava>
</NacistLekovyZaznamLekarDotaz>
</soapenv:Body>
</soapenv:Envelope>
```
### Parametry dotazu (ověřeno proti Cuer2Schema.xsd verze 202501A)
| Element | Povinný | Omezení | Poznámka |
|---|---|---|---|
| `Uzivatel` | ✅ ano | UUID formát | UUID lékaře přidělené SÚKL |
| `Pracoviste` | ✅ ano | — | IČP pracoviště lékaře |
| `PocetZnakuATC` | ✅ ano | **pouze 5 nebo 7** | enum — jiné hodnoty server odmítne |
| `PocetMesicu` | ❌ volitelný | max 99 | počet měsíců do minulosti |
| `Prijmeni` | ✅ ano | — | příjmení pacienta |
| `Jmena` | ✅ ano | — | jméno/jména pacienta |
| `DatumNarozeni` | ✅ ano | `YYYY-MM-DD` | datum narození pacienta |
| `Zastupce` | ❌ volitelný | — | pouze pro zastupujícího lékaře |
| `ID_Zpravy` | ✅ ano | UUID formát | nové UUID pro každý dotaz |
| `Verze` | ✅ ano | — | aktuálně `202501A` |
| `Odeslano` | ✅ ano | ISO 8601 | čas odeslání s časovou zónou |
| `SW_Klienta` | ✅ ano | přesně 12 znaků | doplnit mezerami zleva nebo zprava |
---
## Struktura odpovědi (ověřeno proti Cuer2Schema.xsd verze 202501A)
```
NacistLekovyZaznamOdpoved
├── Doklad
│ ├── Pacient potvrzení identity pacienta
│ │ ├── Jmeno (Prijmeni, Jmena) volitelný
│ │ └── DatumNarozeni volitelný
│ │
│ ├── PredepisujiciSeznam volitelný — lékaři kteří předepisovali
│ │ └── Predepisujici[]
│ │ ├── Lekar Kod (UUID) + Jmeno — volitelný
│ │ ├── ICZ 8 číslic — volitelný
│ │ ├── ICP 8 číslic — povinný
│ │ ├── PZS volitelný
│ │ │ ├── Nazev max 200 znaků
│ │ │ ├── Telefon max 20 znaků — volitelný
│ │ │ └── Adresa
│ │ └── Telefon max 20 znaků — volitelný
│ │
│ ├── VydavajiciSeznam volitelný — lékárníci kteří vydávali
│ │ └── Vydavajici[]
│ │ ├── Lekarnik Kod (UUID) + Jmeno
│ │ └── PZS Nazev + Adresa
│ │
│ ├── PredpisSeznam volitelný — všechny předpisy
│ │ └── Predpis[]
│ │ ├── ID_LP_Predpis UUID předpisu — povinný
│ │ ├── KodPredepisujiciho odkaz do PredepisujiciSeznam — povinný
│ │ ├── DatumVystaveni datum vystavení
│ │ ├── Mnozstvi int, 19999
│ │ ├── Navod max 80 znaků (dávkování)
│ │ ├── Opakovani int — volitelný
│ │ ├── HVLPReg volitelný (registrovaný HVLP)
│ │ ├── HVLPNereg volitelný (neregistrovaný HVLP)
│ │ ├── IPLP volitelný (individuálně připravovaný LP)
│ │ ├── INN volitelný (generický název)
│ │ └── ModryPruh boolean — volitelný
│ │
│ ├── VydejSeznam volitelný — výdeje z lékáren
│ │ └── Vydej[]
│ │ ├── ID_LP_Vydej UUID výdeje
│ │ ├── ID_LP_Predpis UUID předpisu — volitelný (odkaz na předpis)
│ │ ├── KodVydavajiciho odkaz do VydavajiciSeznam — povinný
│ │ ├── DatumVydeje datum výdeje
│ │ ├── Mnozstvi decimal, 0.019999.99
│ │ ├── Navod max 80 znaků
│ │ ├── Exspirace datum — volitelný
│ │ ├── Sarze max 50 znaků
│ │ ├── SerioveCislo max 20 znaků — volitelný
│ │ ├── Pozn max 1000 znaků — volitelný
│ │ ├── HVLPReg volitelný
│ │ ├── HVLPNereg volitelný
│ │ └── IPLP volitelný
│ │
│ └── DuplicitaSeznam volitelný — detekované duplicity výdejů
│ └── Duplicita[]
│ └── ID_LP[]
│ ├── ID_LP_Vydej UUID — volitelný
│ └── ID_LP_Predpis UUID — volitelný
└── Zprava
├── ID_Zpravy echo zpět
├── Verze
├── Odeslano
└── ...
```
> **Poznámka k odkazům:** `KodPredepisujiciho` v předpisu odpovídá `Lekar.Kod` v `PredepisujiciSeznam`.
> Stejně tak `KodVydavajiciho` odpovídá `Lekarnik.Kod` v `VydavajiciSeznam`.
> Struktura je záměrně normalizovaná — lékaři a lékárny jsou uloženi jednou, předpisy a výdeje se na ně odkazují.
Reálná velikost odpovědi: **~227 KB** (pacient s 60měsíční historií).
---
## HTTP hlavičky
```python
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"', # uvozovky jsou součástí hodnoty!
"User-Agent": "Medicus"
}
```
---
## Závislosti (Python)
```
requests
requests-pkcs12
```
Instalace:
```bash
pip install requests requests-pkcs12
```
---
## Jak dohledat správný endpoint (postup pro budoucí operace)
Endpoint `/cuer/Lekar2` byl dohledán tímto postupem:
1. Prohledání veškeré dokumentace SÚKL (20172025) fulltext hledáním výrazu `soap:address`
2. Klíčový dokument: `eRecept_lekovy_zaznam_1v3.docx` (2024-01-18):
> *"Pro webové služby, které používá lékař a klinický farmaceut je nová verze rozhraní 202401A (původní 201912A): `https://lekar-soap.erecept.sukl.cz/cuer/Lekar2`"*
3. Ověřeno živým voláním — HTTP 200, reálná data
### Mapa endpointů IS eRecept (produkce)
| Endpoint | Určen pro | Operace |
|---|---|---|
| `https://lekar-soap.erecept.sukl.cz/cuer/Lekar` | lékař | CUER operace (předpis, zrušení…) |
| `https://lekar-soap.erecept.sukl.cz/cuer/Lekar2` | lékař | **NacistLekovyZaznam**, OverDuplicity, ZjistitPoznamkyHvlp |
| `https://lekar-soap.erecept.sukl.cz/rlpo/Lekar` | lékař | RLPO operace |
| `https://lekarnik-soap.erecept.sukl.cz/cuer/Lekarnik` | lékárník | CUER operace (výdej…) |
| `https://lekarnik-soap.erecept.sukl.cz/cuer/Lekarnik2` | lékárník | nové CUER operace lékárníka |
| `https://cuer-soap.erecept.sukl.cz/` | lékárna, ZP | doplatky, limity pojištěnce |
---
## Ztotožnění pacienta a chybové kódy
Zdroj: živé volání `NacistCiselnikChyb` na `https://lekar-soap.erecept.sukl.cz/cuer/Lekar` — ověřeno 5. 4. 2026.
### Jak funguje ztotožnění pacienta (Registr obyvatel)
Server každý dotaz porovná s **Registrem obyvatel (ROB)**. Lze použít dvě sady údajů:
| Sada | Prvky | Poznámka |
|---|---|---|
| **A — jméno** | Prijmeni + Jmena + DatumNarozeni | základní, stačí pokud je pacient jednoznačný |
| **B — doklad** | DruhDokladu + CisloDokladu | jednoznačné vždy, řeší jmenovce |
Obě sady lze kombinovat. Pokud jsou uvedeny obě, musí být konzistentní (jinak C017).
### Jak přesně probíhá ztotožnění pacienta v ROB
> Zdroj: oficiální dokumentace SÚKL k IS eRecept
IS eRecept nejprve prohledá svůj interní **kmen pacientů** (vlastní databáze dříve ztotožněných osob). Teprve při neúspěchu volá **Registr obyvatel (ROB)** — což může trvat až několik sekund. U každého pacienta s korektními údaji by se to mělo stát pouze jednou. IS eRecept průběžně přebírá změny z ROB (např. přejmenování po svatbě se projeví automaticky).
Způsoby ztotožnění probíhají v tomto pořadí:
#### 1. ECD — elektronicky čitelný doklad
Hledání dle `DruhDokladu` + `CisloDokladu`. Pokud zadáno, má přednost.
#### 2. JPDN — jméno, příjmení, datum narození
Pokud nalezena právě jedna osoba → hotovo (`ROB=JPDN`).
Pokud nalezeno více jmenovců → přechod na JPDNA.
Pokud nenalezena žádná → upozornění (měkká chyba).
#### 3. JPDNA — jméno, příjmení, datum narození + adresa trvalého pobytu
ROB umí automaticky opravit záměnu čísla popisného a orientačního.
Pokud nalezena právě jedna osoba → hotovo (`ROB=JPDNA`).
Pokud nenalezena žádná → upozornění, předpis se uloží s kódem **C023**.
> **Důležité:** Adresu není nutné uvádět, pokud proběhne úspěšné vyhledání bez ní. V takovém případě se na předpisu použije adresa dohledaná v ROB.
> **Cizinci:** Lze uvést zahraniční adresu, nebo adresu hotelu/lázní v ČR.
> **⚠️ Testování:** Ztotožňování reálných osob smí probíhat **pouze na produkci**. O každém ztotožnění je záznam v základních registrech — pacient může obdržet výpis do datové schránky. Na testovacím prostředí jsou dostupné testovací identity na: https://www.szrcr.cz/cs/sluzby/spravci-a-vyvojari/vyvojari-agendovych-informacnich-systemu#testdata (mění se denně mezi 6:006:30).
---
### Hodnoty DruhDokladu
⚠️ **Oprava předchozí dokumentace** — povolených hodnot je více než jen `ID` a `P`:
| Hodnota | Doklad |
|---|---|
| `ID` | občanský průkaz (nový formát) |
| `OP` | občanský průkaz (starší označení) |
| `P` | cestovní pas |
| `IR` | povolení k pobytu |
| `VS` | vízový štítek |
| `PS` | pobytový štítek |
`CisloDokladu` — pouze číslice, max 9 znaků.
---
### Chybové kódy — ztotožnění pacienta (skupina C)
| Kód | Typ | Popis | Co udělat |
|---|---|---|---|
| **C010** | tvrdá | Jméno + příjmení + datum narození nenalezeno v ROB | Zkontrolovat překlep, záměnu jména a příjmení |
| **C011** | tvrdá | Druh a číslo dokladu nenalezeno v ROB | Zkontrolovat číslo a platnost dokladu |
| **C012** | tvrdá | Adresa neodpovídá — více jmenovců | Doplnit `DruhDokladu` + `CisloDokladu` |
| **C014** | tvrdá | Není uvedeno ani jméno/datum, ani číslo dokladu | Doplnit alespoň jednu sadu |
| **C015** | tvrdá | Více jmenovců v ROB, nelze dohledat adresu | Doplnit adresu **nebo** číslo dokladu |
| **C016** | měkká | Pacient mladší 33 dní | Předpis uložen, ale nebude v lékovém záznamu |
| **C017** | tvrdá | Jméno/datum neodpovídá osobě nalezené dle čísla dokladu | Opravit jméno nebo ho neuvádět |
| **C018** | tvrdá | Nelze dohledat, chybí adresa | Doplnit adresu nebo číslo dokladu |
| **C019** | tvrdá | Datum narození v budoucnosti | Opravit datum |
| **C020** | tvrdá | Chybí jméno, příjmení nebo datum narození | Doplnit kompletní sadu |
| **C022** | tvrdá | Pacient dle ROB již zemřel | — |
| **C023** | měkká | Předpis uložen, ale kvůli chybě ztotožnění **nebude v lékovém záznamu** | Opravit identifikaci a provést změnu předpisu |
| **C024** | měkká | Registr LP prohledán, pacient nenalezen v ROB (možný cizinec) | — |
| **C025** | měkká | Výdej uložen, ale kvůli chybě ztotožnění nebude v lékovém záznamu | — |
> **Měkká chyba** = operace proběhla, ale s upozorněním. **Tvrdá chyba** = operace odmítnuta.
### Chybové kódy — doklad totožnosti
| Kód | Popis |
|---|---|
| **L076** | Neznámý druh dokladu — viz tabulka povolených hodnot výše |
### Chybové kódy — systémové
| Kód | Popis |
|---|---|
| **I005** | Registr obyvatel nedostupný (mimo kontrolu SÚKL) — zkusit znovu |
| **I007** | Chyba dotazu na ROB — vstupní data nemají správný formát |
---
### Proč Medicus žádá o občanský průkaz
Typický scénář: lékař pošle dotaz pouze se jménem + datem narození. Pokud existuje více jmenovců v ROB (méně než 1 % obyvatel), server vrátí **C015**. Medicus tento kód rozpozná a zobrazí dialog *"zadejte číslo občanského průkazu"*. Lékař zadá číslo, Medicus pošle dotaz znovu s `DruhDokladu=ID` + `CisloDokladu=...` → server jednoznačně identifikuje pacienta metodou **ECD**.
### Identifikace pro úhradové mechanismy (ZP)
Oddělená od ztotožnění v ROB — probíhá přes **kód ZP + číslo pojištěnce**. IS eRecept číslo pojištěnce **neověřuje** — není garantováno, že je správné. Pokud lékárna zjistí chybu kódu pojišťovny, může ji opravit operací `ZmenitPojistovnuPredpisu`.
### Skript s občankou
`NacistLekovyZaznam_FUNKCNI_OBCANKA.py` — varianta s `DruhDokladu` + `CisloDokladu` v dotazu.
---
## Soubory skriptů
| Skript | Popis |
|---|---|
| `NacistLekovyZaznam_FUNKCNI.py` | základní dotaz — jméno + datum narození |
| `NacistLekovyZaznam_FUNKCNI_OBCANKA.py` | dotaz s číslem občanského průkazu |
| `NacistCiselnikChyb.py` | stáhne kompletní číselník chybových kódů ze serveru |
---
## Zdroje dokumentace SÚKL
| Soubor | Datum | Obsah |
|---|---|---|
| `eRecept_lekovy_zaznam_1v1.docx` | 2020-05-28 | původní popis lékového záznamu |
| `eRecept_lekovy_zaznam_1v3.docx` | 2024-01-18 | endpointy Lekar2/Lekarnik2, verze 202401A |
| `CUERLekarService.wsdl` | 2025-04-24 | nejnovější definice rozhraní, seznam operací |
| `Cuer2Schema.xsd` | 2025-04-24 | kompletní XSD schéma dotazu i odpovědi, verze 202501A |
| `CuerSchema.xsd` | 2025-04-24 | sdílené typy (Zprava, Pristupujici, adresy…) |
@@ -0,0 +1,77 @@
import uuid
from datetime import datetime, timezone
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
# --- Konfigurace ---
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
# HTTP Basic Auth - UUID lékaře (jednoznačný v ČR) + osobní heslo
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINTS = [
"https://lekar-soap.erecept.sukl.cz/cuer/Lekar2",
]
# --- Pacient ---
PRIJMENI = "Buzalka"
JMENA = "Vladimír"
DATUM_NAROZENI = "1973-09-20"
POCET_ZNAKU_ATC = 7
POCET_MESICU = 60
def nacist_lekovy_zaznam():
sess = Session()
sess.mount("https://", Pkcs12Adapter(
pkcs12_filename=PFX_FILE,
pkcs12_password=PFX_PASSWORD
))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
f'<NacistLekovyZaznamLekarDotaz xmlns="http://www.sukl.cz/erp/201912">'
f'<Doklad>'
f'<Pristupujici><Uzivatel>{UZIVATEL}</Uzivatel><Pracoviste>{PRACOVISTE}</Pracoviste></Pristupujici>'
f'<PocetZnakuATC>{POCET_ZNAKU_ATC}</PocetZnakuATC>'
f'<PocetMesicu>{POCET_MESICU}</PocetMesicu>'
f'<Pacient><Totoznost><Jmeno><Prijmeni>{PRIJMENI}</Prijmeni><Jmena>{JMENA}</Jmena></Jmeno>'
f'<DatumNarozeni>{DATUM_NAROZENI}</DatumNarozeni></Totoznost></Pacient>'
f'</Doklad>'
f'<Zprava><ID_Zpravy>{id_zpravy}</ID_Zpravy><Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano><SW_Klienta>MEDICUS_____</SW_Klienta></Zprava>'
f'</NacistLekovyZaznamLekarDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"',
"User-Agent": "Medicus"
}
for url in ENDPOINTS:
print(f"\n--- POST: {url} ---")
try:
resp = sess.post(url, data=soap_body.encode("utf-8"), headers=headers, timeout=15)
print(f"HTTP {resp.status_code} | {len(resp.content)} bytů")
print(resp.text)
except Exception as e:
print(f"CHYBA: {e}")
if __name__ == "__main__":
nacist_lekovy_zaznam()
@@ -0,0 +1,93 @@
import uuid
from datetime import datetime, timezone
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
# --- Konfigurace ---
PFX_FILE = r"C:\Users\vlado\PycharmProjects\Recepty\AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASSWORD = "Vlado7309208104++"
API_USER = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS = "Buzalka@Vladimir2025"
UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINT = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar2"
NAMESPACE = "http://www.sukl.cz/erp/201912"
# --- Pacient ---
PRIJMENI = "Buzalka"
JMENA = "Vladimír"
DATUM_NAROZENI = "1973-09-20"
# --- Doklad totožnosti ---
# DruhDokladu: "ID" = občanský průkaz, "P" = cestovní pas
# CisloDokladu: číslo dokladu, max 9 znaků (jen číslice)
DRUH_DOKLADU = "ID"
CISLO_DOKLADU = "" # <-- sem vyplnit číslo občanského průkazu pacienta
POCET_ZNAKU_ATC = 7 # pouze 5 nebo 7
POCET_MESICU = 60 # max 99, volitelné
def nacist_lekovy_zaznam_s_obcankou():
if not CISLO_DOKLADU:
print("CHYBA: Není vyplněno CISLO_DOKLADU!")
return
sess = Session()
sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASSWORD))
sess.auth = (API_USER, API_PASS)
id_zpravy = str(uuid.uuid4())
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
soap_body = (
'<?xml version="1.0" encoding="UTF-8"?>'
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
'<soapenv:Body>'
f'<NacistLekovyZaznamLekarDotaz xmlns="{NAMESPACE}">'
f'<Doklad>'
f'<Pristupujici>'
f'<Uzivatel>{UZIVATEL}</Uzivatel>'
f'<Pracoviste>{PRACOVISTE}</Pracoviste>'
f'</Pristupujici>'
f'<PocetZnakuATC>{POCET_ZNAKU_ATC}</PocetZnakuATC>'
f'<PocetMesicu>{POCET_MESICU}</PocetMesicu>'
f'<Pacient>'
f'<Totoznost>'
f'<Jmeno><Prijmeni>{PRIJMENI}</Prijmeni><Jmena>{JMENA}</Jmena></Jmeno>'
f'<DatumNarozeni>{DATUM_NAROZENI}</DatumNarozeni>'
f'<DruhDokladu>{DRUH_DOKLADU}</DruhDokladu>'
f'<CisloDokladu>{CISLO_DOKLADU}</CisloDokladu>'
f'</Totoznost>'
f'</Pacient>'
f'</Doklad>'
f'<Zprava>'
f'<ID_Zpravy>{id_zpravy}</ID_Zpravy>'
f'<Verze>202501A</Verze>'
f'<Odeslano>{odeslano}</Odeslano>'
f'<SW_Klienta>MEDICUS_____</SW_Klienta>'
f'</Zprava>'
f'</NacistLekovyZaznamLekarDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistLekovyZaznam"',
"User-Agent": "Medicus"
}
print(f"Pacient: {PRIJMENI} {JMENA}, nar. {DATUM_NAROZENI}")
print(f"Doklad: {DRUH_DOKLADU} {CISLO_DOKLADU}")
print(f"Volám: {ENDPOINT}\n")
resp = sess.post(ENDPOINT, data=soap_body.encode("utf-8"), headers=headers, timeout=15)
print(f"HTTP {resp.status_code} | {len(resp.content)} bytů\n")
print(resp.text)
if __name__ == "__main__":
nacist_lekovy_zaznam_s_obcankou()
@@ -0,0 +1,194 @@
"""
Reimport vsech XML souboru z xml_archive do MySQL — bez volani API.
Pouziti:
python reimport_z_xml.py # vsechna XML z 2026-04-11
python reimport_z_xml.py xml_archive/2026-04-11 # konkretni adresar
python reimport_z_xml.py xml_archive # vsechny podadresare rekurzivne
"""
import sys
import importlib.util
from pathlib import Path
from datetime import date
import fdb
import pymysql
import pymysql.cursors
# Windows konzole
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(errors="replace")
# ── Konfigurace ───────────────────────────────────────────────────────────────
XML_ADRESAR = Path(__file__).parent / "xml_archive" / "2026-04-11"
FB = dict(
dsn = r"localhost:c:\medicus 3\data\medicus.fdb",
user = "SYSDBA",
password = "masterkey",
charset = "win1250",
)
DB = dict(
host = "192.168.1.76",
user = "root",
password = "Vlado9674+",
database = "medicus",
charset = "utf8mb4",
cursorclass = pymysql.cursors.DictCursor,
)
ICP = "09305001"
ODB = "001"
# ─────────────────────────────────────────────────────────────────────────────
# Nacteni parsovaci logiky z 06UlozitDoMySQL.py
_spec = importlib.util.spec_from_file_location(
"m06", Path(__file__).parent / "06UlozitDoMySQL.py"
)
_m06 = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_m06)
parsuj_xml = _m06.parsuj_xml
uloz = _m06.uloz
inicializuj_schema = _m06.inicializuj_schema
def nacti_pacienty_z_fb():
"""Vrati slovnik {(prijmeni_upper, datnar): idpac} ze vsech pacientu v Medicusu."""
conn = fdb.connect(**FB)
try:
cur = conn.cursor()
dnes = date.today().isoformat()
cur.execute("""
SELECT KAR.IDPAC, KAR.PRIJMENI, KAR.JMENO, KAR.DATNAR
FROM KAR
WHERE KAR.vyrazen = 'N'
AND EXISTS (
SELECT 1 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 = ?
AND i.odb = ?
)
""", (dnes, dnes, ICP, ODB))
result = {}
for row in cur.fetchall():
idpac, prijmeni, jmeno, datnar = row
klic = (prijmeni.strip().upper(), datnar)
result[klic] = {"idpac": idpac, "prijmeni": prijmeni.strip(), "jmeno": jmeno.strip(), "datnar": datnar}
print(f"Firebird: nacteno {len(result)} registrovanych pacientu")
return result
finally:
conn.close()
def upsert_pacient(cur, pac):
cur.execute("""
INSERT INTO pacient (idpac, prijmeni, jmena, datum_narozeni)
VALUES (%s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
prijmeni = VALUES(prijmeni),
jmena = VALUES(jmena)
""", (pac["idpac"], pac["prijmeni"], pac["jmeno"], pac["datnar"]))
cur.execute("SELECT id FROM pacient WHERE idpac = %s", (pac["idpac"],))
return cur.fetchone()["id"]
def main():
# Adresar z argumentu nebo default
adresar = Path(sys.argv[1]) if len(sys.argv) > 1 else XML_ADRESAR
if not adresar.is_dir():
sys.exit(f"Adresar neexistuje: {adresar}")
# Najdi vsechna XML rekurzivne
xml_soubory = sorted(adresar.rglob("*.xml"))
if not xml_soubory:
sys.exit(f"Zadne XML soubory nalezeny v: {adresar}")
print(f"Nalezeno {len(xml_soubory)} XML souboru v: {adresar}")
# Nacti pacienty z Firebirdu
fb_pacienti = nacti_pacienty_z_fb()
# Pripoj se k MySQL a inicializuj schema
conn = pymysql.connect(**DB)
try:
inicializuj_schema(conn)
ok = chyba = preskoceno = 0
p_celkem = v_celkem = 0
for i, xml_path in enumerate(xml_soubory, 1):
rel = xml_path.relative_to(Path(__file__).parent)
try:
zprava, predpisy, vydeji, predepisujici, vydavajici = parsuj_xml(xml_path)
except Exception as e:
print(f"[{i:4}/{len(xml_soubory)}] {xml_path.name:<45} CHYBA parsovani: {e}")
chyba += 1
continue
# Zjisti prijmeni a datum narozeni z XML odpovedi
pac_prijmeni = (zprava.get("pacient_prijmeni") or "").upper()
pac_datnar = zprava.get("pacient_datum_narozeni") # string YYYY-MM-DD nebo None
# Prevod na date objekt pro porovnani s Firebirdem
if pac_datnar and isinstance(pac_datnar, str):
try:
from datetime import datetime
pac_datnar_d = datetime.strptime(pac_datnar[:10], "%Y-%m-%d").date()
except ValueError:
pac_datnar_d = None
elif hasattr(pac_datnar, "year"):
pac_datnar_d = pac_datnar
else:
pac_datnar_d = None
klic = (pac_prijmeni, pac_datnar_d)
fb_pac = fb_pacienti.get(klic)
if not fb_pac:
# Pacient neni registrovan — uloz bez idpac (bude ignorovan pri hromadnem behu)
# Zkus najit v MySQL podle jmena a data
with conn.cursor() as cur:
cur.execute(
"SELECT id FROM pacient WHERE prijmeni = %s AND datum_narozeni = %s",
(zprava.get("pacient_prijmeni"), pac_datnar)
)
row = cur.fetchone()
if row:
pacient_id = row["id"]
else:
preskoceno += 1
print(f"[{i:4}/{len(xml_soubory)}] {xml_path.name:<45} PRESKOCENO (neni v registru)")
continue
else:
with conn.cursor() as cur:
pacient_id = upsert_pacient(cur, fb_pac)
conn.commit()
try:
stats = uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
pacient_id=pacient_id, xml_soubor=str(rel))
conn.commit()
p_celkem += stats["predpisy_novych"]
v_celkem += stats["vydeji_novych"]
print(f"[{i:4}/{len(xml_soubory)}] {xml_path.name:<45} OK "
f"{stats['predpisy_novych']:3}p {stats['vydeji_novych']:3}v")
ok += 1
except Exception as e:
conn.rollback()
print(f"[{i:4}/{len(xml_soubory)}] {xml_path.name:<45} CHYBA ukladani: {e}")
chyba += 1
print()
print(f"Hotovo: {ok} OK, {chyba} chyb, {preskoceno} preskoceno")
print(f"Celkem vlozeno: {p_celkem} predpisu, {v_celkem} vydejuu")
finally:
conn.close()
if __name__ == "__main__":
main()
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>ADAMEC</Prijmeni><Jmena>PETR</Jmena></Jmeno><DatumNarozeni>1981-01-19</DatumNarozeni></Pacient><PredepisujiciSeznam /><VydavajiciSeznam /><PredpisSeznam /><VydejSeznam /><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>CC97F0EA-5522-4D5F-99B3-E187C9421C43</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:09:14.5490742+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>F6BDB49A-4974-4134-AD62-645DDE5E6DE4</ID_Podani><Prijato>2026-04-11T12:09:14.3577236+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>ADLEROVÁ</Prijmeni><Jmena>IRENA</Jmena></Jmeno><DatumNarozeni>1937-07-05</DatumNarozeni></Pacient><PredepisujiciSeznam><Predepisujici><Lekar><Kod>83607a3f-d44d-42e2-b4eb-57a983ec4d0c</Kod><Jmeno><Prijmeni>Buzalková</Prijmeni><Jmena>Michaela</Jmena></Jmeno></Lekar><ICZ>09305000</ICZ><ICP>09305001</ICP><PZS><Nazev>MUDr. Michaela Buzalková</Nazev><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>19000</PSC></Adresa></PZS><Telefon>266010136</Telefon></Predepisujici><Predepisujici><Lekar><Kod>455cff31-b5ea-460c-ad81-907dec80fe0d</Kod><Jmeno><Prijmeni>Tychka</Prijmeni><Jmena>Viktoriia</Jmena></Jmeno></Lekar><ICP>09246001</ICP><PZS><Nazev>Derma CZ s.r.o.</Nazev><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha - Prosek</NazevObce><PSC>19000</PSC></Adresa></PZS><Telefon>266 010 225</Telefon></Predepisujici></PredepisujiciSeznam><VydavajiciSeznam><Vydavajici><Lekarnik><Kod>50957296-9aac-4366-8e82-286bbb2079a5</Kod><Jmeno><Prijmeni>Moravcová</Prijmeni><Jmena>Marie</Jmena></Jmeno></Lekarnik><PZS><Nazev>Hrouda CZ s.r.o.</Nazev><Telefon>228229843</Telefon><Adresa><NazevUlice>Chlumčanského</NazevUlice><CisloPopisne>497</CisloPopisne><CisloOrientacni>5</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>18000</PSC></Adresa></PZS></Vydavajici><Vydavajici><Lekarnik><Kod>563bcaba-b5d9-4102-9086-f8cc7399b58f</Kod><Jmeno><Prijmeni>Sokolová</Prijmeni><Jmena>Pavlína</Jmena></Jmeno></Lekarnik><PZS><Nazev>ČESKÁ LÉKÁRNA HOLDING, a.s.</Nazev><Telefon>225574234</Telefon><Adresa><NazevUlice>Vysočanská</NazevUlice><CisloPopisne>242</CisloPopisne><CisloOrientacni>111</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>19000</PSC></Adresa></PZS></Vydavajici></VydavajiciSeznam><PredpisSeznam><Predpis><ID_LP_Predpis>92A0A7AA-DA19-4683-9E4E-7B7038522AEA</ID_LP_Predpis><KodPredepisujiciho>83607a3f-d44d-42e2-b4eb-57a983ec4d0c</KodPredepisujiciho><DatumVystaveni>2026-04-10</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>1-0-0</Navod><HVLPReg><Kod>0265451</Kod><ATC>A12AX</ATC><Nazev>CALCICHEW D3 LEMON</Nazev><Forma>TBL MND</Forma><Sila>500MG/400IU</Sila><CestaPodani>POR</CestaPodani><Baleni>60</Baleni></HVLPReg></Predpis><Predpis><ID_LP_Predpis>8082AD1E-69C7-4D28-AF48-271649BB8D91</ID_LP_Predpis><KodPredepisujiciho>455cff31-b5ea-460c-ad81-907dec80fe0d</KodPredepisujiciho><DatumVystaveni>2026-03-17</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>2x týdně</Navod><HVLPReg><Kod>0045304</Kod><ATC>D01AE16</ATC><Nazev>LOCERYL</Nazev><Forma>LAC UGC</Forma><Sila>50MG/ML</Sila><CestaPodani>DRM</CestaPodani><Baleni>1X2,5ML I</Baleni></HVLPReg></Predpis></PredpisSeznam><VydejSeznam><Vydej><ID_LP_Vydej>3B60510F-548D-4B2E-9D8F-B46166DD01B4</ID_LP_Vydej><ID_LP_Predpis>92A0A7AA-DA19-4683-9E4E-7B7038522AEA</ID_LP_Predpis><KodVydavajiciho>50957296-9aac-4366-8e82-286bbb2079a5</KodVydavajiciho><DatumVydeje>2026-04-10</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>1-0-0</Navod><Sarze>12523499</Sarze><HVLPReg><Kod>0265451</Kod><ATC>A12AX</ATC><Nazev>CALCICHEW D3 LEMON</Nazev><Forma>TBL MND</Forma><Sila>500MG/400IU</Sila><CestaPodani>POR</CestaPodani><Baleni>60</Baleni></HVLPReg></Vydej><Vydej><ID_LP_Vydej>4B067971-E978-40D2-A7C3-B48044542BFF</ID_LP_Vydej><ID_LP_Predpis>8082AD1E-69C7-4D28-AF48-271649BB8D91</ID_LP_Predpis><KodVydavajiciho>563bcaba-b5d9-4102-9086-f8cc7399b58f</KodVydavajiciho><DatumVydeje>2026-03-17</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>2x týdně</Navod><Exspirace>2028-08-31</Exspirace><Sarze>5212458</Sarze><HVLPReg><Kod>0185977</Kod><ATC>D01AE16</ATC><Nazev>LOCERYL</Nazev><Forma>LAC UGC</Forma><Sila>50MG/ML</Sila><CestaPodani>DRM</CestaPodani><Baleni>1X2,5ML II</Baleni></HVLPReg></Vydej></VydejSeznam><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>3A657B88-E7F7-4078-9A9A-E693AB1C27F7</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:09:31.3646059+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>804C8B7E-6BC8-4388-BEE8-46CF9C824C4F</ID_Podani><Prijato>2026-04-11T12:09:31.1458623+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>ALEXOVIČOVÁ</Prijmeni><Jmena>JULIE</Jmena></Jmeno><DatumNarozeni>1978-10-27</DatumNarozeni></Pacient><PredepisujiciSeznam /><VydavajiciSeznam /><PredpisSeznam /><VydejSeznam /><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>3D01F477-6BB9-45E0-8063-BECC18F77F5A</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:10:02.5458887+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>1805D199-B265-4C10-B011-DE8EBA7C6225</ID_Podani><Prijato>2026-04-11T12:10:02.4017063+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>ANDERLE</Prijmeni><Jmena>PETR</Jmena></Jmeno><DatumNarozeni>1975-02-07</DatumNarozeni></Pacient><PredepisujiciSeznam /><VydavajiciSeznam /><PredpisSeznam /><VydejSeznam /><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>4E402F97-C38C-4494-9D38-5561E80D7595</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:10:18.6298555+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>8A79C9BF-BBCF-42FE-9931-584D97D81FF1</ID_Podani><Prijato>2026-04-11T12:10:18.3798287+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>BILLOUZ</Prijmeni><Jmena>DAVID MAURICE JEAN</Jmena></Jmeno><DatumNarozeni>1973-12-04</DatumNarozeni></Pacient><PredepisujiciSeznam><Predepisujici><Lekar><Kod>53484083-fabc-4d6a-97ae-12cf43d80783</Kod><Jmeno><Prijmeni>Buzalková</Prijmeni><Jmena>Michaela</Jmena></Jmeno></Lekar><ICZ>09305000</ICZ><ICP>09305001</ICP><PZS><Nazev>MUDr. Michaela Buzalková</Nazev><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>19000</PSC></Adresa></PZS><Telefon>266010136</Telefon></Predepisujici><Predepisujici><Lekar><Kod>aa587d67-541f-4111-88b6-24741ab770bb</Kod><Jmeno><Prijmeni>Bludovský</Prijmeni><Jmena>Jaroslav</Jmena></Jmeno></Lekar><ICZ>09085000</ICZ><ICP>09085001</ICP><PZS><Nazev>MUDr. Jaroslav Bludovský</Nazev><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha 9</NazevObce><PSC>19000</PSC></Adresa></PZS><Telefon>266010235</Telefon></Predepisujici></PredepisujiciSeznam><VydavajiciSeznam><Vydavajici><Lekarnik><Kod>0edfa837-89b2-4b6d-b13f-0cdde919524a</Kod><Jmeno><Prijmeni>Škodová</Prijmeni><Jmena>Eva</Jmena></Jmeno></Lekarnik><PZS><Nazev>Poliklinika Prosek a.s.</Nazev><Telefon>266010257</Telefon><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>19000</PSC></Adresa></PZS></Vydavajici><Vydavajici><Lekarnik><Kod>a3278ff1-5f58-446f-a1be-7abbbbe9d3d0</Kod><Jmeno><Prijmeni>Langová</Prijmeni><Jmena>Michaela</Jmena></Jmeno></Lekarnik><PZS><Nazev>BENU Česká republika s.r.o.</Nazev><Telefon>703462221</Telefon><Adresa><NazevUlice>Střelničná</NazevUlice><CisloPopisne>2270</CisloPopisne><CisloOrientacni>46</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>18000</PSC></Adresa></PZS></Vydavajici><Vydavajici><Lekarnik><Kod>5390a32a-191f-403f-ae13-f34b259df0f0</Kod><Jmeno><Prijmeni>Radoňová</Prijmeni><Jmena>Daniela</Jmena></Jmeno></Lekarnik><PZS><Nazev>Poliklinika Prosek a.s.</Nazev><Telefon>266010257</Telefon><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha 9</NazevObce><PSC>19000</PSC></Adresa></PZS></Vydavajici></VydavajiciSeznam><PredpisSeznam><Predpis><ID_LP_Predpis>95174A02-5182-4B2B-9357-4C900E6D75AC</ID_LP_Predpis><KodPredepisujiciho>53484083-fabc-4d6a-97ae-12cf43d80783</KodPredepisujiciho><DatumVystaveni>2025-12-11</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>dle pp max 14 dnů</Navod><HVLPReg><Kod>0262102</Kod><ATC>D07AB02</ATC><Nazev>LOCOID LIPOCREAM 0,1%</Nazev><Forma>CRM</Forma><Sila>1MG/G</Sila><CestaPodani>DRM</CestaPodani><Baleni>1X30G</Baleni></HVLPReg></Predpis><Predpis><ID_LP_Predpis>65518391-85C6-47D6-BD71-B12C2CCB6943</ID_LP_Predpis><KodPredepisujiciho>53484083-fabc-4d6a-97ae-12cf43d80783</KodPredepisujiciho><DatumVystaveni>2025-10-20</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>dle návodu</Navod><HVLPReg><Kod>0237830</Kod><ATC>R01AX06</ATC><Nazev>BACTROBAN NASAL</Nazev><Forma>NAS UNG</Forma><Sila>20MG/G</Sila><CestaPodani>NAS</CestaPodani><Baleni>1X3G</Baleni></HVLPReg></Predpis><Predpis><ID_LP_Predpis>BB2DF7E4-18BD-4DB3-8799-DA8E5D555587</ID_LP_Predpis><KodPredepisujiciho>53484083-fabc-4d6a-97ae-12cf43d80783</KodPredepisujiciho><DatumVystaveni>2025-03-03</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>1-1-0</Navod><HVLPReg><Kod>0092757</Kod><ATC>R05CB15</ATC><Nazev>ERDOMED</Nazev><Forma>CPS DUR</Forma><Sila>300MG</Sila><CestaPodani>POR</CestaPodani><Baleni>10</Baleni></HVLPReg></Predpis><Predpis><ID_LP_Predpis>7ABDCBD1-A5CC-4188-B9B8-0F8E005DADC7</ID_LP_Predpis><KodPredepisujiciho>aa587d67-541f-4111-88b6-24741ab770bb</KodPredepisujiciho><DatumVystaveni>2024-11-07</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>uk</Navod><IPLP><PostupPripravy>Sol. alum. acet.-tartarici 4,0
Sol. acidi borici 1,5% 12,0
Spir. vini diluti ad 20,0
MDS. ušní kapky 3x denně po 2 do obou uší</PostupPripravy><Nazev>UK Alsol</Nazev></IPLP></Predpis></PredpisSeznam><VydejSeznam><Vydej><ID_LP_Vydej>935C6BD3-ED97-49F5-BDAB-257BE1B699A4</ID_LP_Vydej><ID_LP_Predpis>95174A02-5182-4B2B-9357-4C900E6D75AC</ID_LP_Predpis><KodVydavajiciho>0edfa837-89b2-4b6d-b13f-0cdde919524a</KodVydavajiciho><DatumVydeje>2025-12-11</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>dle pp max 14 dnů</Navod><Sarze>24L17A</Sarze><Pozn>Neuvedena</Pozn><HVLPReg><Kod>0262102</Kod><ATC>D07AB02</ATC><Nazev>LOCOID LIPOCREAM 0,1%</Nazev><Forma>CRM</Forma><Sila>1MG/G</Sila><CestaPodani>DRM</CestaPodani><Baleni>1X30G</Baleni></HVLPReg></Vydej><Vydej><ID_LP_Vydej>BF36F2FB-B19A-47BB-B189-2E04ECE51CBD</ID_LP_Vydej><ID_LP_Predpis>65518391-85C6-47D6-BD71-B12C2CCB6943</ID_LP_Predpis><KodVydavajiciho>a3278ff1-5f58-446f-a1be-7abbbbe9d3d0</KodVydavajiciho><DatumVydeje>2025-10-20</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>dle návodu</Navod><Sarze>AY7Y</Sarze><HVLPReg><Kod>0237830</Kod><ATC>R01AX06</ATC><Nazev>BACTROBAN NASAL</Nazev><Forma>NAS UNG</Forma><Sila>20MG/G</Sila><CestaPodani>NAS</CestaPodani><Baleni>1X3G</Baleni></HVLPReg></Vydej><Vydej><ID_LP_Vydej>5076BA10-3929-48F0-8A86-6F934F33051E</ID_LP_Vydej><ID_LP_Predpis>BB2DF7E4-18BD-4DB3-8799-DA8E5D555587</ID_LP_Predpis><KodVydavajiciho>5390a32a-191f-403f-ae13-f34b259df0f0</KodVydavajiciho><DatumVydeje>2025-03-03</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>1-1-0</Navod><Sarze>0599</Sarze><Pozn>Neuvedena</Pozn><HVLPReg><Kod>0092757</Kod><ATC>R05CB15</ATC><Nazev>ERDOMED</Nazev><Forma>CPS DUR</Forma><Sila>300MG</Sila><CestaPodani>POR</CestaPodani><Baleni>10</Baleni></HVLPReg></Vydej><Vydej><ID_LP_Vydej>5EEC1651-1A7B-45DF-B14E-F000775EF6E3</ID_LP_Vydej><ID_LP_Predpis>7ABDCBD1-A5CC-4188-B9B8-0F8E005DADC7</ID_LP_Predpis><KodVydavajiciho>5390a32a-191f-403f-ae13-f34b259df0f0</KodVydavajiciho><DatumVydeje>2024-11-07</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>uk</Navod><Sarze>20241106037</Sarze><Pozn>Neuvedena</Pozn><IPLP><KodVZP>0001002</KodVZP><Nazev>Ušní kapky se sol.alumin.acetico tartar.</Nazev><Slozka><Mnozstvi>1</Mnozstvi><Jednotka>ks</Jednotka><Nazev>PO Příprava čistých obalů sk.2.1.1</Nazev><Sarze>NA</Sarze></Slozka><Slozka><Mnozstvi>1</Mnozstvi><Jednotka>ks</Jednotka><Nazev>Lékovka hnědá s pipetou 25ml**</Nazev><Sarze>F280324</Sarze></Slozka><Slozka><Mnozstvi>1</Mnozstvi><Jednotka>ks</Jednotka><Nazev>TP Dispenzace sk.1.11</Nazev><Sarze>NA</Sarze></Slozka><Slozka><Mnozstvi>20</Mnozstvi><Jednotka>ks</Jednotka><Nazev>Taxa laborum ...</Nazev><Sarze>NA</Sarze></Slozka><Slozka><Mnozstvi>20</Mnozstvi><Jednotka>g</Jednotka><Nazev>Ušní kapky se sol. alumin.acet.tartar.MEZIPRODUKT</Nazev><Sarze>20241106029</Sarze></Slozka><Slozka><Mnozstvi>1</Mnozstvi><Jednotka>ks</Jednotka><Nazev>SIGNATURA NOVÁ</Nazev><Sarze>260224</Sarze></Slozka></IPLP></Vydej></VydejSeznam><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>C610F496-AF68-453E-BDB6-8640AF8E0559</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:20:25.5419241+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>734EC9EB-69E6-4114-9A67-202E376837F0</ID_Podani><Prijato>2026-04-11T12:20:25.3192135+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>BUZALKA</Prijmeni><Jmena>VLADIMÍR</Jmena></Jmeno><DatumNarozeni>2003-08-02</DatumNarozeni></Pacient><PredepisujiciSeznam /><VydavajiciSeznam /><PredpisSeznam /><VydejSeznam /><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>1C34C759-CF78-4788-A1EE-8C30AFB5A58B</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:32:58.4738373+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>2C05838C-658C-4C69-8A5A-BF99D7DE5D7D</ID_Podani><Prijato>2026-04-11T12:32:58.3288862+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NacistLekovyZaznamOdpoved xmlns="http://www.sukl.cz/erp/201912"><Doklad><Pacient><Jmeno><Prijmeni>BUZALKOVÁ</Prijmeni><Jmena>MICHAELA</Jmena></Jmeno><DatumNarozeni>2007-09-05</DatumNarozeni></Pacient><PredepisujiciSeznam><Predepisujici><Lekar><Kod>cae47885-9e51-468f-86b1-3a9d9bb3447b</Kod><Jmeno><Prijmeni>Buzalka</Prijmeni><Jmena>Vladimír</Jmena></Jmeno></Lekar><ICZ>09305000</ICZ><ICP>09305001</ICP><PZS><Nazev>MUDr. Michaela Buzalková</Nazev><Adresa><NazevUlice>Lovosická</NazevUlice><CisloPopisne>440</CisloPopisne><CisloOrientacni>40</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>19000</PSC></Adresa></PZS><Telefon>266010136</Telefon></Predepisujici></PredepisujiciSeznam><VydavajiciSeznam><Vydavajici><Lekarnik><Kod>3b709dea-bf11-49b0-8897-9de3b57e0fb4</Kod><Jmeno><Prijmeni>Hefjuková</Prijmeni><Jmena>Anna</Jmena></Jmeno></Lekarnik><PZS><Nazev>ČESKÁ LÉKÁRNA HOLDING, a.s.</Nazev><Telefon>225574455</Telefon><Adresa><NazevUlice>Kostelecká</NazevUlice><CisloPopisne>822</CisloPopisne><CisloOrientacni>75</CisloOrientacni><NazevObce>Praha</NazevObce><PSC>19600</PSC></Adresa></PZS></Vydavajici></VydavajiciSeznam><PredpisSeznam><Predpis><ID_LP_Predpis>48721638-DFCC-47E5-B89F-FC184D60E8B8</ID_LP_Predpis><KodPredepisujiciho>cae47885-9e51-468f-86b1-3a9d9bb3447b</KodPredepisujiciho><DatumVystaveni>2026-03-13</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>při bolesti</Navod><HVLPReg><Kod>0017187</Kod><ATC>M01AX17</ATC><Nazev>NIMESIL</Nazev><Forma>POR GRA SUS</Forma><Sila>100MG</Sila><CestaPodani>POR</CestaPodani><Baleni>30</Baleni></HVLPReg></Predpis><Predpis><ID_LP_Predpis>BCF0AA03-2603-46D7-B571-FD205186BEE5</ID_LP_Predpis><KodPredepisujiciho>cae47885-9e51-468f-86b1-3a9d9bb3447b</KodPredepisujiciho><DatumVystaveni>2026-03-13</DatumVystaveni><Mnozstvi>1</Mnozstvi><Navod>1-0-0</Navod><HVLPReg><Kod>0155685</Kod><ATC>R06AE07</ATC><Nazev>ZYRTEC</Nazev><Forma>TBL FLM</Forma><Sila>10MG</Sila><CestaPodani>POR</CestaPodani><Baleni>50</Baleni></HVLPReg></Predpis></PredpisSeznam><VydejSeznam><Vydej><ID_LP_Vydej>CAB3980B-D50B-4FB3-9BDF-D838C1A870F8</ID_LP_Vydej><ID_LP_Predpis>48721638-DFCC-47E5-B89F-FC184D60E8B8</ID_LP_Predpis><KodVydavajiciho>3b709dea-bf11-49b0-8897-9de3b57e0fb4</KodVydavajiciho><DatumVydeje>2026-03-13</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>při bolesti</Navod><Exspirace>2028-11-30</Exspirace><Sarze>54970</Sarze><HVLPReg><Kod>0017187</Kod><ATC>M01AX17</ATC><Nazev>NIMESIL</Nazev><Forma>POR GRA SUS</Forma><Sila>100MG</Sila><CestaPodani>POR</CestaPodani><Baleni>30</Baleni></HVLPReg></Vydej><Vydej><ID_LP_Vydej>E409ADF5-2F2A-4A55-858C-CC0CE97D0731</ID_LP_Vydej><ID_LP_Predpis>BCF0AA03-2603-46D7-B571-FD205186BEE5</ID_LP_Predpis><KodVydavajiciho>3b709dea-bf11-49b0-8897-9de3b57e0fb4</KodVydavajiciho><DatumVydeje>2026-03-13</DatumVydeje><Mnozstvi>1</Mnozstvi><Navod>1-0-0</Navod><Exspirace>2028-09-30</Exspirace><Sarze>381624</Sarze><HVLPReg><Kod>0155685</Kod><ATC>R06AE07</ATC><Nazev>ZYRTEC</Nazev><Forma>TBL FLM</Forma><Sila>10MG</Sila><CestaPodani>POR</CestaPodani><Baleni>50</Baleni></HVLPReg></Vydej></VydejSeznam><DuplicitaSeznam /></Doklad><Zprava><ID_Zpravy>CA219D0B-89F7-4E74-BD55-55017160D9E3</ID_Zpravy><Verze>202501A</Verze><Odeslano>2026-04-11T12:33:31.67695+02:00</Odeslano><Aplikace>Informační systém eRecept, v. 1.108.2.22758</Aplikace><ID_Podani>1192D3D7-6B00-414C-A2B6-0CB0F2EFC4F2</ID_Podani><Prijato>2026-04-11T12:33:31.5176122+02:00</Prijato></Zprava></NacistLekovyZaznamOdpoved></soap:Body></soap:Envelope>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More