notebookvb

This commit is contained in:
2026-04-06 09:27:48 +02:00
parent 921c69e908
commit 36295bfbb0
3 changed files with 200 additions and 32 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()
@@ -276,44 +276,78 @@ Server každý dotaz porovná s **Registrem obyvatel (ROB)**. Lze použít dvě
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 |
| `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 | Popis | Co udělat |
|---|---|---|
| **C010** | Jméno + příjmení + datum narození nenalezeno v ROB | Zkontrolovat překlep, záměnu jména a příjmení |
| **C011** | Druh a číslo dokladu nenalezeno v ROB | Zkontrolovat číslo a platnost dokladu |
| **C012** | Adresa neodpovídá — více jmenovců se stejným jménem a datem | Doplnit `DruhDokladu` + `CisloDokladu` |
| **C014** | Není uvedeno ani jméno/datum, ani číslo dokladu | Doplnit alespoň jednu sadu |
| **C015** | Více jmenovců v ROB, nelze dohledat adresu | Doplnit adresu **nebo** číslo dokladu |
| **C016** | Pacient mladší 33 dní | Předpis uložen, ale nebude v lékovém záznamu |
| **C017** | Jméno/datum neodpovídá osobě nalezené dle čísla dokladu | Opravit jméno nebo ho neuvádět |
| **C018** | Nelze dohledat, chybí adresa | Doplnit adresu nebo číslo dokladu |
| **C019** | Datum narození v budoucnosti | Opravit datum |
| **C020** | Chybí jméno, příjmení nebo datum narození | Doplnit kompletní sadu A |
| **C022** | Pacient dle ROB již zemřel | — |
| 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 | — |
### Chybové kódy — upozornění (uloženo, ale bez záznamu)
| Kód | Popis |
|---|---|
| **C023** | Předpis uložen, ale kvůli chybě ztotožnění nebude v lékovém záznamu |
| **C024** | Registr LP prohledán, pacient nenalezen v ROB (možný cizinec) |
| **C025** | 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 — povoleno pouze `ID` (občanský průkaz) nebo `P` (cestovní pas) |
| **L076** | Neznámý druh dokladu — viz tabulka povolených hodnot výše |
### Chybové kódy — systémové
@@ -322,9 +356,15 @@ Obě sady lze kombinovat. Pokud jsou uvedeny obě, musí být konzistentní (jin
| **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, 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 vrátí jednoznačný výsledek.
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
@@ -222,18 +222,68 @@ NacteniPredpisuOdpoved
└── Prijato datetime — čas přijetí na serveru
```
### Hodnoty stavu receptu (`Stav`)
### Popis jednotlivých polí odpovědi (zdroj: `documentationCuer.html` SÚKL 2025-04-24)
| Pole | Typ | Povinné | Popis |
|---|---|---|---|
| `ID_Dokladu` | string 1225 | ✅ | Identifikátor dokladu |
| `DatumVystaveni` | date | ✅ | Datum vystavení eReceptu |
| `PlatnostDo` | date | ✅ | Datum konce platnosti eReceptu určené při předepsání |
| `VypisDo` | date | ❌ | Datum prodloužení platnosti eReceptu (lékárna může platnost prodloužit výpisem) |
| `Akutni` | boolean | ❌ | Symbol Akutní péče nebo Neodkladná péče |
| `Rodina` | boolean | ❌ | Symbol „Pro potřebu rodiny" nebo „Ad usum proprium" (lékař předepisuje sobě/rodině) |
| `Preshranicni` | boolean | ❌ | Přeshraniční předpis *(nepoužívá se)* |
| `Opakovani` | long | ❌ | Celkový počet výdejů u opakovacích receptů |
| `Pacient` | nacteni_pacient_type | ✅ | Údaje o pacientovi |
| `Predepisujici` | nacteni_predepisujici_type | ✅ | Údaje o předepisujícím lékaři |
| `Doporucujici` | nacteni_doporucujici_type | ❌ | Údaje o doporučujícím lékaři |
| `Revize` | nacteni_revize_type | ❌ | Schválení revizním lékařem ZP *(nepoužívá se)* |
| `PLP` | nacteni_predepsany_lp_erp_type[] | ❌ | Předepsané položky (léky) |
| `Pozn` | string 11000 | ❌ | Poznámka na eReceptu |
| `UpozornitLekare` | enum | ❌ | Akceptace zpětného předání poznámky z lékárny — viz tabulka níže |
| `Stav` | enum | ✅ | Stav eReceptu — viz tabulka níže |
| `Vydej` | nacteni_zkraceny_vydej_erp_doklad_odpoved_type[] | ❌ | Seznam výdejů uskutečněných dosud na tento eRecept |
| `Zmena` | dateTime | ✅ | Datum a čas poslední změny eReceptu |
| `Zalozeni` | dateTime | ✅ | Datum a čas založení eReceptu |
| `DruhPojisteni` | enum | ❌ | Druh pojištění pacienta — viz tabulka níže |
| `ModryPruh` | boolean | ❌ | Předpis na LP s obsahem vysoce návykové látky (omamné/psychotropní) |
| `Papirovy` | boolean | ❌ | Digitalizovaný papírový předpis *(nepoužívá se)* |
| `ZapocitatelnyDoplatekZbyvaDoLimitu` | decimal 0999999.99 | ❌ | Částka zbývající do max. ročního limitu započitatelných doplatků pacienta (po překročení limitu ZP hradí doplatky za pacienta) |
---
### Hodnoty stavu receptu (`Stav`) — enum `stav_elektronickeho_receptu`
| Hodnota | Popis |
|---|---|
| `KE_SCHVALENI` | čeká na schválení revizním lékařem ZP |
| `ZAMITNUTY` | zamítnut |
| `PREDEPSANY` | vystaven, čeká na výdej |
| `PRIPRAVOVANY` | lékárna si ho načetla, připravuje výdej |
| `CASTECNE_VYDANY` | vydán částečně (opakovací předpis) |
| `PLNE_VYDANY` | kompletně vydán ✅ |
| `NEDOKONCENY_VYDEJ` | výdej nedokončen |
| `UZAVRENY` | uzavřen, nelze měnit |
| `KE_SCHVALENI` | *(Nepoužívá se)* Ke schválení zdravotní pojišťovnou |
| `ZAMITNUTY` | *(Nepoužívá se)* Zamítnutý zdravotní pojišťovnou |
| `PREDEPSANY` | Předepsaný — výchozí stav po založení, lze provést výdej |
| `PRIPRAVOVANY` | Připravovaný — lékárna pracuje na výdeji (připravuje IPLP nebo objednala HVLP u distributora); výdej může provést jen tato lékárna; používá se i pro blokaci při technickém výpadku |
| `CASTECNE_VYDANY` | Částečně vydaný — výdej proběhl, ale může následovat další (prodloužená platnost nebo opakovací recept s dalšími opakováními) |
| `PLNE_VYDANY` | Plně vydaný — výdej dokončen, žádný další výdej nenásleduje ✅ |
| `NEDOKONCENY_VYDEJ` | Nedokončený výdej — lékárna nevydala léčivo, ale zaznamenala doplňující informaci (důvod nevydání); lze použít pouze u prvního takového výdeje |
| `UZAVRENY` | *(Nepoužívá se)* Uzavřený |
### Hodnoty druhu pojištění (`DruhPojisteni`) — enum `druh_pojisteni`
| Hodnota | Popis |
|---|---|
| `NEZADANO` | Nezadáno |
| `VEREJNE` | Veřejné zdravotní pojištění (běžný případ v ČR) |
| `SMLUVNI_PRIPOJISTENI` | Smluvní připojištění |
| `CESTOVNI_PRIPOJISTENI` | Cestovní zdravotní připojištění |
| `POJISTENI_EU` | Pojištění EU (pacient z jiného státu EU) |
### Hodnoty upozornění lékaře (`UpozornitLekare`) — enum `upozornit_lekare`
Lékárník může k výdeji přidat poznámku pro předepisujícího lékaře. Toto pole říká, zda lékař tuto funkci akceptoval a jak urgentně chce být informován.
| Hodnota | Popis |
|---|---|
| `BEZODKLADNE` | Upozornit lékaře bezodkladně (akceptuje BEZODKLADNE i PRISTI_NAVSTEVA) |
| `PRISTI_NAVSTEVA` | Upozornit lékaře při příští návštěvě pacienta (akceptuje pouze PRISTI_NAVSTEVA) |
| *(neuvedeno)* | Lékař neakceptoval zpětné předávání poznámek z lékárny |
### Hodnoty způsobu ztotožnění (`ROB`)