Files
recept/NačteníPředpisuWithClaude/08StahnoutPredpisy.py
T
2026-04-14 07:20:28 +02:00

190 lines
6.8 KiB
Python

"""
Stazeni detailu receptu (NacistPredpis) pro poslednich N receptu z Medicusu.
Spusteni:
python 08StahnoutPredpisy.py # 10 receptu od 2025-01-01
python 08StahnoutPredpisy.py --limit 50 # 50 receptu
python 08StahnoutPredpisy.py --od 2026-01-01
Pauza mezi volanimi: 5 sekund.
XML odpovedi se ukladaji do xml_archive/YYYY-MM-DD/ERP_kod.xml
"""
import sys
import time
import uuid
from datetime import datetime, timezone, date
from pathlib import Path
import fdb
from requests import Session
from requests_pkcs12 import Pkcs12Adapter
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(errors="replace")
# ── 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/Lekar"
NAMESPACE = "http://www.sukl.cz/erp/201704"
PAUZA = 5 # sekund
# ── Konfigurace Firebird ─────────────────────────────────────────────────────
FB_DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
FB_USER = 'SYSDBA'
FB_PASS = 'masterkey'
FB_CHARSET = 'win1250'
# ── Adresare ─────────────────────────────────────────────────────────────────
XML_DIR = Path(__file__).parent / "xml_archive"
def nacti_erp_kody(fb_conn, datum_od, limit, prijmeni=None):
"""Nacte unikatni ID_Dokladu (erp kody) z Firebirdu — recept_epodani.erp."""
sql = """
SELECT FIRST ? r.datum, r.lek, r.dop, r.idpac,
TRIM(kar.prijmeni) AS prijmeni, TRIM(kar.jmeno) AS jmeno,
ep.erp
FROM recept r
JOIN recept_epodani ep ON r.id_epodani = ep.id
JOIN kar ON r.idpac = kar.idpac
WHERE r.datum >= ? AND ep.erp IS NOT NULL
"""
params = [limit, datum_od]
if prijmeni:
placeholders = ",".join(["?"] * len(prijmeni))
sql += f" AND UPPER(TRIM(kar.prijmeni)) IN ({placeholders})"
params.extend(p.upper() for p in prijmeni)
sql += " ORDER BY r.datum DESC"
cur = fb_conn.cursor()
cur.execute(sql, params)
rows = cur.fetchall()
cur.close()
# deduplikace dle erp kodu — zachovat prvni vyskyt (nejnovejsi datum)
seen = set()
unique = []
for row in rows:
erp = row[6]
if erp not in seen:
seen.add(erp)
unique.append(row)
return unique
def volej_nacist_predpis(sess, erp_kod):
"""Zavola NacistPredpis a vrati (status_code, response_text)."""
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'<NacteniPredpisuDotaz xmlns="{NAMESPACE}">'
f'<Doklad>'
f'<Pristupujici>'
f'<Uzivatel>{UZIVATEL}</Uzivatel>'
f'<Pracoviste>{PRACOVISTE}</Pracoviste>'
f'</Pristupujici>'
f'<Identifikator>'
f'<ID_Dokladu>{erp_kod}</ID_Dokladu>'
f'</Identifikator>'
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'</NacteniPredpisuDotaz>'
'</soapenv:Body>'
'</soapenv:Envelope>'
)
headers = {
"Content-Type": 'text/xml; charset="UTF-8"',
"SOAPAction": '"NacistPredpis"',
"User-Agent": "Medicus",
}
resp = sess.post(ENDPOINT, data=soap_body.encode("utf-8"), headers=headers, timeout=15)
return resp.status_code, resp.text
## ── Parametry (uprav zde) ────────────────────────────────────────────────────
LIMIT = 100 # max pocet receptu ke stazeni
DATUM_OD = "2025-01-01" # recepty od tohoto data
PRIJMENI = ["Buzalka"] # filtr prijmeni (list), nebo None = vsichni
## ─────────────────────────────────────────────────────────────────────────────
def main():
datum_od = DATUM_OD
dnes = date.today().isoformat()
out_dir = XML_DIR / dnes
out_dir.mkdir(parents=True, exist_ok=True)
# Firebird
print(f"Pripojuji Firebird...")
fb = fdb.connect(dsn=FB_DSN, user=FB_USER, password=FB_PASS, charset=FB_CHARSET)
rows = nacti_erp_kody(fb, datum_od, LIMIT, PRIJMENI)
fb.close()
print(f"Nacteno {len(rows)} receptu z Medicusu (od {datum_od})\n")
if not rows:
print("Zadne recepty k stazeni.")
return
# SOAP session
sess = Session()
sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASS))
sess.auth = (API_USER, API_PASS)
ok = 0
chyby = 0
for i, row in enumerate(rows, 1):
datum_rec, lek, dop, idpac, prijmeni, jmeno, erp_kod = row
lek_str = f"{lek} {dop}".strip() if dop else str(lek).strip()
label = f"{prijmeni} {jmeno}".strip()
print(f"[{i:4d}/{len(rows)}] {label:30s} {erp_kod} ", end="", flush=True)
try:
status, text = volej_nacist_predpis(sess, erp_kod)
if status == 200 and "<soap:Fault" not in text and "Fault>" not in text:
xml_file = out_dir / f"{erp_kod}.xml"
xml_file.write_text(text, encoding="utf-8")
size_kb = len(text.encode("utf-8")) / 1024
print(f"OK {size_kb:6.1f} KB {lek_str[:40]}")
ok += 1
else:
# SOAP Fault nebo HTTP chyba
chyba_short = text[:120].replace("\n", " ")
print(f"CHYBA HTTP {status} {chyba_short}")
# ulozit i chybovou odpoved
xml_file = out_dir / f"{erp_kod}_CHYBA.xml"
xml_file.write_text(text, encoding="utf-8")
chyby += 1
except Exception as e:
print(f"EXCEPTION {e}")
chyby += 1
if i < len(rows):
time.sleep(PAUZA)
print(f"\nHotovo: {ok} OK, {chyby} chyb")
print(f"XML: {out_dir}")
if __name__ == "__main__":
main()