notebookvb
This commit is contained in:
@@ -579,6 +579,11 @@ def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
|
|||||||
Ulozi parsovana data do MySQL.
|
Ulozi parsovana data do MySQL.
|
||||||
pacient_id — FK na tabulku pacient (None pokud volano primo z 06)
|
pacient_id — FK na tabulku pacient (None pokud volano primo z 06)
|
||||||
xml_soubor — relativni cesta k archivnimu XML souboru (None pokud neni archivovano)
|
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_predpisu = 0
|
||||||
iplp_vydejuu = 0
|
iplp_vydejuu = 0
|
||||||
@@ -604,7 +609,6 @@ def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
|
|||||||
stazeno = CURRENT_TIMESTAMP
|
stazeno = CURRENT_TIMESTAMP
|
||||||
""", zprava_row)
|
""", zprava_row)
|
||||||
zprava_id = _najdi_id(cur, "zprava", "id_zpravy", zprava["id_zpravy"])
|
zprava_id = _najdi_id(cur, "zprava", "id_zpravy", zprava["id_zpravy"])
|
||||||
print(f" zprava id={zprava_id} ({zprava['id_zpravy']})")
|
|
||||||
|
|
||||||
# ── predpisy + jejich slozky ───────────────────────────────────────────
|
# ── predpisy + jejich slozky ───────────────────────────────────────────
|
||||||
vlozeno_p = 0
|
vlozeno_p = 0
|
||||||
@@ -640,9 +644,6 @@ def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
|
|||||||
""", s)
|
""", s)
|
||||||
vlozeno_ps += 1
|
vlozeno_ps += 1
|
||||||
|
|
||||||
print(f" predpisy: {vlozeno_p} novych (celkem {len(predpisy)})")
|
|
||||||
print(f" predpis_slozka: {vlozeno_ps} slozek z {iplp_predpisu} IPLP predpisu")
|
|
||||||
|
|
||||||
# ── vydeji + jejich slozky ────────────────────────────────────────────
|
# ── vydeji + jejich slozky ────────────────────────────────────────────
|
||||||
vlozeno_v = 0
|
vlozeno_v = 0
|
||||||
vlozeno_vs = 0
|
vlozeno_vs = 0
|
||||||
@@ -679,11 +680,7 @@ def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
|
|||||||
""", s)
|
""", s)
|
||||||
vlozeno_vs += 1
|
vlozeno_vs += 1
|
||||||
|
|
||||||
print(f" vydeji: {vlozeno_v} novych (celkem {len(vydeji)})")
|
|
||||||
print(f" vydej_slozka: {vlozeno_vs} slozek z {iplp_vydejuu} IPLP vydejuu")
|
|
||||||
|
|
||||||
# ── predepisujici ─────────────────────────────────────────────────────
|
# ── predepisujici ─────────────────────────────────────────────────────
|
||||||
vlozeno_pre = 0
|
|
||||||
for row in predepisujici:
|
for row in predepisujici:
|
||||||
if not row.get("lekar_kod"):
|
if not row.get("lekar_kod"):
|
||||||
continue
|
continue
|
||||||
@@ -705,11 +702,8 @@ def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
|
|||||||
psc = VALUES(psc),
|
psc = VALUES(psc),
|
||||||
telefon = VALUES(telefon)
|
telefon = VALUES(telefon)
|
||||||
""", row)
|
""", row)
|
||||||
vlozeno_pre += cur.rowcount
|
|
||||||
print(f" predepisujici: {vlozeno_pre} radku (celkem {len(predepisujici)})")
|
|
||||||
|
|
||||||
# ── vydavajici ────────────────────────────────────────────────────────
|
# ── vydavajici ────────────────────────────────────────────────────────
|
||||||
vlozeno_vyd = 0
|
|
||||||
for row in vydavajici:
|
for row in vydavajici:
|
||||||
if not row.get("lekarnik_kod"):
|
if not row.get("lekarnik_kod"):
|
||||||
continue
|
continue
|
||||||
@@ -729,11 +723,18 @@ def uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici,
|
|||||||
psc = VALUES(psc),
|
psc = VALUES(psc),
|
||||||
telefon = VALUES(telefon)
|
telefon = VALUES(telefon)
|
||||||
""", row)
|
""", row)
|
||||||
vlozeno_vyd += cur.rowcount
|
|
||||||
print(f" vydavajici: {vlozeno_vyd} radku (celkem {len(vydavajici)})")
|
|
||||||
|
|
||||||
conn.commit()
|
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 ──────────────────────────────────────────────────────────────────────
|
# ── main ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -751,7 +752,10 @@ def main():
|
|||||||
try:
|
try:
|
||||||
vytvor_schema(conn)
|
vytvor_schema(conn)
|
||||||
print("Ukladani ...")
|
print("Ukladani ...")
|
||||||
uloz(conn, zprava, predpisy, vydeji, predepisujici, vydavajici)
|
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")
|
print("Hotovo OK")
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
@@ -8,9 +8,16 @@ Spusteni:
|
|||||||
# vsichni registrovani pacienti
|
# vsichni registrovani pacienti
|
||||||
python 07StahnoutVsechny.py
|
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:
|
Logika poctu mesicu:
|
||||||
- prvni stazeni pacienta → 60 mesicu (maximum)
|
- prvni stazeni pacienta → 60 mesicu (maximum)
|
||||||
- opakowane stazeni → ceil(pocet_dni_od_posledniho / 30) + 1
|
- opakovane stazeni → ceil(pocet_dni_od_posledniho / 30) + 1
|
||||||
(prekryv 1 mesic pro jistotu, INSERT IGNORE zajisti bez duplikatu)
|
(prekryv 1 mesic pro jistotu, INSERT IGNORE zajisti bez duplikatu)
|
||||||
|
|
||||||
XML archiv:
|
XML archiv:
|
||||||
@@ -20,14 +27,12 @@ XML archiv:
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
import logging
|
||||||
import math
|
import math
|
||||||
|
import random
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
# Windows konzole — nahrad neunikatni znaky misto padu
|
|
||||||
if hasattr(sys.stdout, "reconfigure"):
|
|
||||||
sys.stdout.reconfigure(errors="replace")
|
|
||||||
from datetime import datetime, timezone, date
|
from datetime import datetime, timezone, date
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from xml.sax.saxutils import escape as xml_escape
|
from xml.sax.saxutils import escape as xml_escape
|
||||||
@@ -38,6 +43,10 @@ import pymysql.cursors
|
|||||||
from requests import Session
|
from requests import Session
|
||||||
from requests_pkcs12 import Pkcs12Adapter
|
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 ──────────────────────────────────────────────
|
# ── Import parsovaci logiky z 06 ──────────────────────────────────────────────
|
||||||
_spec = importlib.util.spec_from_file_location(
|
_spec = importlib.util.spec_from_file_location(
|
||||||
"m06", Path(__file__).parent / "06UlozitDoMySQL.py"
|
"m06", Path(__file__).parent / "06UlozitDoMySQL.py"
|
||||||
@@ -58,9 +67,10 @@ UZIVATEL = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
|
|||||||
PRACOVISTE = "00214235367"
|
PRACOVISTE = "00214235367"
|
||||||
ENDPOINT = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar2"
|
ENDPOINT = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar2"
|
||||||
|
|
||||||
POCET_ZNAKU_ATC = 7
|
POCET_ZNAKU_ATC = 7
|
||||||
POCET_MESICU_MAX = 60
|
POCET_MESICU_MAX = 60
|
||||||
PAUZA_MEZI_VOLANIMI = 15 # sekund
|
PAUZA_MIN = 10 # sekund
|
||||||
|
PAUZA_MAX = 20 # sekund
|
||||||
|
|
||||||
# ── Konfigurace Firebird ──────────────────────────────────────────────────────
|
# ── Konfigurace Firebird ──────────────────────────────────────────────────────
|
||||||
FB_DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
FB_DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
||||||
@@ -80,8 +90,36 @@ DB = dict(
|
|||||||
cursorclass = pymysql.cursors.DictCursor,
|
cursorclass = pymysql.cursors.DictCursor,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── XML archiv ────────────────────────────────────────────────────────────────
|
# ── Adresare ──────────────────────────────────────────────────────────────────
|
||||||
XML_DIR = Path(__file__).parent / "xml_archive"
|
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 ─────────────────────────────────
|
# ── Firebird: nacteni registrovanych pacientu ─────────────────────────────────
|
||||||
@@ -121,10 +159,6 @@ _SQL_FILTR = """
|
|||||||
|
|
||||||
|
|
||||||
def nacti_pacienty(prijmeni_filtr=None):
|
def nacti_pacienty(prijmeni_filtr=None):
|
||||||
"""
|
|
||||||
Vraci seznam dict {idpac, prijmeni, jmeno, datnar}.
|
|
||||||
prijmeni_filtr: list prijmeni (napr. ['Buzalka', 'Buzalkova']) nebo None = vsichni.
|
|
||||||
"""
|
|
||||||
conn = fdb.connect(dsn=FB_DSN, user=FB_USER, password=FB_PASS, charset=FB_CHARSET)
|
conn = fdb.connect(dsn=FB_DSN, user=FB_USER, password=FB_PASS, charset=FB_CHARSET)
|
||||||
try:
|
try:
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
@@ -143,10 +177,6 @@ def nacti_pacienty(prijmeni_filtr=None):
|
|||||||
# ── MySQL: pacient UPSERT ─────────────────────────────────────────────────────
|
# ── MySQL: pacient UPSERT ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
def upsert_pacient(cur, pac):
|
def upsert_pacient(cur, pac):
|
||||||
"""
|
|
||||||
Vlozi nebo aktualizuje pacienta v tabulce pacient.
|
|
||||||
Vraci MySQL id radku.
|
|
||||||
"""
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO pacient (idpac, prijmeni, jmena, datum_narozeni)
|
INSERT INTO pacient (idpac, prijmeni, jmena, datum_narozeni)
|
||||||
VALUES (%s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s)
|
||||||
@@ -159,7 +189,6 @@ def upsert_pacient(cur, pac):
|
|||||||
|
|
||||||
|
|
||||||
def posledni_stazeni(cur, pacient_id):
|
def posledni_stazeni(cur, pacient_id):
|
||||||
"""Vraci datetime posledniho stazeni, nebo None pro noveho pacienta."""
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT MAX(stazeno) AS posledni FROM zprava WHERE pacient_id = %s",
|
"SELECT MAX(stazeno) AS posledni FROM zprava WHERE pacient_id = %s",
|
||||||
(pacient_id,)
|
(pacient_id,)
|
||||||
@@ -169,52 +198,13 @@ def posledni_stazeni(cur, pacient_id):
|
|||||||
|
|
||||||
|
|
||||||
def vypocti_pocet_mesicu(posledni):
|
def vypocti_pocet_mesicu(posledni):
|
||||||
"""60 pro prvni stazeni, jinak delta v mesicich + 1 (prekryv)."""
|
|
||||||
if posledni is None:
|
if posledni is None:
|
||||||
return POCET_MESICU_MAX
|
return POCET_MESICU_MAX
|
||||||
delta_dni = (datetime.now() - posledni).days
|
delta_dni = (datetime.now() - posledni).days
|
||||||
return min(math.ceil(delta_dni / 30) + 1, POCET_MESICU_MAX)
|
return min(math.ceil(delta_dni / 30) + 1, POCET_MESICU_MAX)
|
||||||
|
|
||||||
|
|
||||||
# ── SOAP volani ───────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
def extrahuj_soap_fault(xml_text):
|
|
||||||
"""
|
|
||||||
Pokud XML obsahuje SOAP Fault, vraci text chyby (str).
|
|
||||||
Pokud je odpoved v poradku, vraci 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"
|
|
||||||
# Zkontroluj SOAP Fault
|
|
||||||
fault = body.find(f"{{{NS_SOAP}}}Fault")
|
|
||||||
if fault is None:
|
|
||||||
fault = body.find("Fault") # nektery server posila bez namespace
|
|
||||||
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
|
|
||||||
# Zkontroluj, ze odpoved je spravneho typu (NacistLekovyZaznamOdpoved)
|
|
||||||
odpoved = body.find(f"{{{NS_SUKL}}}NacistLekovyZaznamOdpoved")
|
|
||||||
if odpoved is None:
|
|
||||||
# Neznamy format — vrat prvni tag jako info
|
|
||||||
first = list(body)
|
|
||||||
tag = first[0].tag if first else "prazdne Body"
|
|
||||||
return f"Neocekavana odpoved: {tag}"
|
|
||||||
return None # vse OK
|
|
||||||
except Exception as e:
|
|
||||||
return f"Chyba pri parsovani odpovedi: {e}"
|
|
||||||
|
|
||||||
|
|
||||||
def uloz_poznamku(conn, pacient_id, poznamka):
|
def uloz_poznamku(conn, pacient_id, poznamka):
|
||||||
"""Ulozi nebo vymaze poznamku (chybu) u pacienta."""
|
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"UPDATE pacient SET poznamka = %s WHERE id = %s",
|
"UPDATE pacient SET poznamka = %s WHERE id = %s",
|
||||||
@@ -223,14 +213,39 @@ def uloz_poznamku(conn, pacient_id, poznamka):
|
|||||||
conn.commit()
|
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):
|
def nacti_lekovy_zaznam(sess, prijmeni, jmena, datum_narozeni, pocet_mesicu):
|
||||||
"""
|
|
||||||
Zavola NacistLekovyZaznam pro jednoho pacienta.
|
|
||||||
Vraci xml_text (str). Vyhazuje RuntimeError pri HTTP chybe.
|
|
||||||
"""
|
|
||||||
id_zpravy = str(uuid.uuid4())
|
id_zpravy = str(uuid.uuid4())
|
||||||
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
|
odeslano = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")
|
||||||
|
|
||||||
soap = (
|
soap = (
|
||||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||||
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
|
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
|
||||||
@@ -259,7 +274,6 @@ def nacti_lekovy_zaznam(sess, prijmeni, jmena, datum_narozeni, pocet_mesicu):
|
|||||||
'</soapenv:Body>'
|
'</soapenv:Body>'
|
||||||
'</soapenv:Envelope>'
|
'</soapenv:Envelope>'
|
||||||
)
|
)
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": 'text/xml; charset="UTF-8"',
|
"Content-Type": 'text/xml; charset="UTF-8"',
|
||||||
"SOAPAction": '"NacistLekovyZaznam"',
|
"SOAPAction": '"NacistLekovyZaznam"',
|
||||||
@@ -274,10 +288,6 @@ def nacti_lekovy_zaznam(sess, prijmeni, jmena, datum_narozeni, pocet_mesicu):
|
|||||||
# ── XML archiv ────────────────────────────────────────────────────────────────
|
# ── XML archiv ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str):
|
def uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str):
|
||||||
"""
|
|
||||||
Ulozi XML do xml_archive/YYYY-MM-DD/{Prijmeni}_{Jmena}_{datnar}.xml
|
|
||||||
Vraci relativni cestu (str) vuci adresari skriptu.
|
|
||||||
"""
|
|
||||||
adr = XML_DIR / dnes_str
|
adr = XML_DIR / dnes_str
|
||||||
adr.mkdir(parents=True, exist_ok=True)
|
adr.mkdir(parents=True, exist_ok=True)
|
||||||
nazev = f"{prijmeni}_{jmena}_{datnar_str}.xml".replace(" ", "_")
|
nazev = f"{prijmeni}_{jmena}_{datnar_str}.xml".replace(" ", "_")
|
||||||
@@ -289,131 +299,128 @@ def uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str):
|
|||||||
# ── Hlavni smycka ─────────────────────────────────────────────────────────────
|
# ── Hlavni smycka ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
ap = argparse.ArgumentParser(
|
ap = argparse.ArgumentParser(description="Hromadne stazeni lekovych zaznamu z eReceptu")
|
||||||
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(
|
ap.add_argument("--limit", type=int, default=None, help="Zpracuj pouze N pacientu")
|
||||||
"--prijmeni",
|
ap.add_argument("--offset", type=int, default=0,
|
||||||
help="Filtr prijmeni oddelena carkou, napr: Buzalka,Buzalkova,Kusinova",
|
help="Preskoc prvnich N pacientu (pro postupne davkovani)")
|
||||||
default=None,
|
|
||||||
)
|
|
||||||
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()
|
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
|
prijmeni_filtr = None
|
||||||
if args.prijmeni:
|
if args.prijmeni:
|
||||||
prijmeni_filtr = [p.strip() for p in args.prijmeni.split(",")]
|
prijmeni_filtr = [p.strip() for p in args.prijmeni.split(",")]
|
||||||
print(f"Filtr prijmeni: {prijmeni_filtr}")
|
log.info(f"Filtr prijmeni: {prijmeni_filtr}")
|
||||||
|
|
||||||
# 1. Nacti pacienty z Medicusu
|
log.info("Nacitam pacienty z Medicusu...")
|
||||||
print("Nacitam pacienty z Medicusu (Firebird)...")
|
|
||||||
pacienti = nacti_pacienty(prijmeni_filtr)
|
pacienti = nacti_pacienty(prijmeni_filtr)
|
||||||
print(f" Nalezeno: {len(pacienti)} pacientu")
|
log.debug(f"Celkem registrovanych: {len(pacienti)}")
|
||||||
|
|
||||||
if args.offset:
|
if args.offset:
|
||||||
pacienti = pacienti[args.offset:]
|
pacienti = pacienti[args.offset:]
|
||||||
print(f" Preskoceno: {args.offset} (--offset {args.offset})")
|
log.debug(f"Preskoceno: {args.offset}")
|
||||||
if args.limit:
|
if args.limit:
|
||||||
pacienti = pacienti[:args.limit]
|
pacienti = pacienti[:args.limit]
|
||||||
print(f" Omezeno na: {len(pacienti)} (--limit {args.limit})")
|
log.debug(f"Omezeno na: {len(pacienti)}")
|
||||||
if not pacienti:
|
|
||||||
print("Zadni pacienti — konec.")
|
celkem = len(pacienti)
|
||||||
|
log.info(f"Pacientu ke zpracovani: {celkem} | log: {log_soubor.name}")
|
||||||
|
|
||||||
|
if not celkem:
|
||||||
|
log.info("Zadni pacienti — konec.")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 2. Pripoj se k MySQL, over schema (CREATE IF NOT EXISTS)
|
|
||||||
print("Pripojuji k MySQL...")
|
|
||||||
conn = pymysql.connect(**DB)
|
conn = pymysql.connect(**DB)
|
||||||
inicializuj_schema(conn)
|
inicializuj_schema(conn)
|
||||||
|
log.debug("MySQL schema OK")
|
||||||
|
|
||||||
# 3. Priprav SOAP session (sdilena pro vsechny pacienty)
|
|
||||||
sess = Session()
|
sess = Session()
|
||||||
sess.mount("https://", Pkcs12Adapter(
|
sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASS))
|
||||||
pkcs12_filename=PFX_FILE,
|
|
||||||
pkcs12_password=PFX_PASS,
|
|
||||||
))
|
|
||||||
sess.auth = (API_USER, API_PASS)
|
sess.auth = (API_USER, API_PASS)
|
||||||
|
|
||||||
dnes_str = date.today().isoformat()
|
|
||||||
ok = 0
|
ok = 0
|
||||||
chyby = 0
|
chyby = 0
|
||||||
celkem = len(pacienti)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for i, pac in enumerate(pacienti, 1):
|
for i, pac in enumerate(pacienti, 1):
|
||||||
prijmeni = pac["prijmeni"]
|
prijmeni = pac["prijmeni"]
|
||||||
jmena = pac["jmeno"]
|
jmena = pac["jmeno"]
|
||||||
datnar = pac["datnar"]
|
datnar = pac["datnar"]
|
||||||
datnar_str = datnar.isoformat() if hasattr(datnar, "isoformat") else str(datnar)
|
datnar_str = datnar.isoformat() if hasattr(datnar, "isoformat") else str(datnar)
|
||||||
|
jmeno_str = f"{prijmeni} {jmena}"
|
||||||
|
|
||||||
print(f"\n[{i}/{celkem}] {prijmeni} {jmena} (*{datnar_str})")
|
log.debug(f"[{i:4}/{celkem}] {jmeno_str} (*{datnar_str})")
|
||||||
|
|
||||||
# UPSERT pacienta, zjisti kdy byl naposledy stazen
|
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
pacient_id = upsert_pacient(cur, pac)
|
pacient_id = upsert_pacient(cur, pac)
|
||||||
posledni = posledni_stazeni(cur, pacient_id)
|
posledni = posledni_stazeni(cur, pacient_id)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
pocet_mesicu = vypocti_pocet_mesicu(posledni)
|
pocet_mesicu = vypocti_pocet_mesicu(posledni)
|
||||||
print(f" Stahuju {pocet_mesicu} mesicu "
|
log.debug(f" stahuju {pocet_mesicu}m "
|
||||||
f"(posledni stazeni: {posledni.strftime('%Y-%m-%d') if posledni else 'nikdy'})")
|
f"(posledni: {posledni.strftime('%Y-%m-%d') if posledni else 'nikdy'})")
|
||||||
|
|
||||||
# Zavolej API
|
# Zavolej API
|
||||||
try:
|
try:
|
||||||
xml_text = nacti_lekovy_zaznam(sess, prijmeni, jmena, datnar_str, pocet_mesicu)
|
xml_text = nacti_lekovy_zaznam(sess, prijmeni, jmena, datnar_str, pocet_mesicu)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
zprava_chyby = str(e)[:400]
|
zprava_chyby = str(e)[:400]
|
||||||
print(f" CHYBA API: {zprava_chyby}")
|
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)
|
uloz_poznamku(conn, pacient_id, zprava_chyby)
|
||||||
chyby += 1
|
chyby += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Detekuj SOAP Fault v odpovedi (HTTP 200 ale chyba uvnitr)
|
# Detekuj SOAP Fault
|
||||||
soap_fault = extrahuj_soap_fault(xml_text)
|
soap_fault = extrahuj_soap_fault(xml_text)
|
||||||
if soap_fault:
|
if soap_fault:
|
||||||
print(f" SOAP FAULT: {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])
|
uloz_poznamku(conn, pacient_id, soap_fault[:400])
|
||||||
chyby += 1
|
chyby += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Uloz XML na disk
|
# Uloz XML
|
||||||
xml_soubor = uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str)
|
xml_soubor = uloz_xml_na_disk(xml_text, prijmeni, jmena, datnar_str, dnes_str)
|
||||||
xml_path = Path(__file__).parent / xml_soubor
|
xml_path = Path(__file__).parent / xml_soubor
|
||||||
print(f" XML: {xml_soubor} ({xml_path.stat().st_size // 1024} KB)")
|
kb = xml_path.stat().st_size // 1024
|
||||||
|
log.debug(f" XML: {xml_soubor} ({kb} KB)")
|
||||||
|
|
||||||
# Parsuj + uloz do MySQL
|
# Parsuj + uloz do MySQL
|
||||||
try:
|
try:
|
||||||
zprava_d, predpisy, vydeji, predepisujici, vydavajici = parsuj_xml(xml_path)
|
zprava_d, predpisy, vydeji, predepisujici, vydavajici = parsuj_xml(xml_path)
|
||||||
uloz(conn, zprava_d, predpisy, vydeji, predepisujici, vydavajici,
|
stats = uloz(conn, zprava_d, predpisy, vydeji, predepisujici, vydavajici,
|
||||||
pacient_id=pacient_id, xml_soubor=xml_soubor)
|
pacient_id=pacient_id, xml_soubor=xml_soubor)
|
||||||
uloz_poznamku(conn, pacient_id, None) # vymaz predchozi chybu
|
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
|
ok += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
zprava_chyby = str(e)[:400]
|
zprava_chyby = str(e)[:400]
|
||||||
print(f" CHYBA parsovani/ulozeni: {zprava_chyby}")
|
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)
|
uloz_poznamku(conn, pacient_id, zprava_chyby)
|
||||||
chyby += 1
|
chyby += 1
|
||||||
|
|
||||||
# Pauza mezi volanimi API (neplati po poslednim pacientovi)
|
|
||||||
if i < celkem:
|
if i < celkem:
|
||||||
print(f" Cekam {PAUZA_MEZI_VOLANIMI}s ...")
|
pauza = random.randint(PAUZA_MIN, PAUZA_MAX)
|
||||||
time.sleep(PAUZA_MEZI_VOLANIMI)
|
log.debug(f" cekam {pauza}s ...")
|
||||||
|
time.sleep(pauza)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
sess.close()
|
sess.close()
|
||||||
|
|
||||||
print(f"\n{'=' * 55}")
|
zhrnutí = f"Hotovo: {ok} OK | {chyby} chyb | celkem {celkem} pacientu"
|
||||||
print(f"Hotovo: {ok} OK | {chyby} chyb | celkem {celkem} pacientu")
|
log.info("=" * 55)
|
||||||
|
log.info(zhrnutí)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user