Files
Vladimir Buzalka 4c81529718 notebookvb
2026-04-27 07:02:24 +02:00

7.2 KiB
Raw Permalink Blame History

Ověření pojistného statusu pacientů (VZP B2B)

Systém pro automatické ověřování, zda jsou registrovaní pacienti platně pojištěni u zdravotní pojišťovny. Dotazuje VZP B2B API, ukládá historii do MySQL a generuje PDF reporty o neshodách.


Architektura

Medicus Firebird DB (192.168.1.4)
    └─ get_active_registered_patients()
           │
           ▼
   VZPB2BClient.stav_pojisteni()   ←─ mTLS (PFX certifikát)
   prod.b2b.vzp.cz/stavPojisteniB2B
           │
           ▼
   MySQL medevio.vzp_stav_pojisteni
           │
           ▼
   Reportovací skript
   └─ binární hledání data zlomu pojištění
   └─ Jinja2 + WeasyPrint → PDF

Soubory

20 Ověření proti Medicus/
├── 10 FinalSaveInsuranceStatusScript(R).py   ← sběr dat (spouštět denně)
├── 10 Ověření proti medicus.py               ← generování PDF reportu
├── insurance_check.log                       ← log sběru dat
└── Output/
    └── kontrola_pojisteni_YYYY-MM-DD_HH-MM-SS.pdf

Sdílené knihovny (knihovny/)

Soubor Třída Popis
medicus_db.py MedicusDB Wrapper pro Firebird připojení k Medicus
vzpb2b_client.py VZPB2BClient VZP B2B SOAP API klient s mTLS

Skript 1: FinalSaveInsuranceStatusScript

Soubor: 10 FinalSaveInsuranceStatusScript(R).py

Inkrementální sběr pojistných stavů. Lze spouštět opakovaně — při druhém spuštění ve stejný den přeskočí již zkontrolované pacienty.

Postup

  1. Načte všechny aktivně registrované pacienty z Medicus (registr.priznak IN ('A','D','V'), kar.vyrazen <> 'A')
  2. Pro každého pacienta zkontroluje MAX(k_datu) v MySQL — pokud je dnešní, přeskočí ho
  3. Zavolá VZP B2B stavPojisteniB2B SOAP endpoint
  4. Uloží XML odpověď + parsovaná data do tabulky vzp_stav_pojisteni
  5. Mezi dotazy čeká 1,4 s (ochrana proti přetížení VZP API)

Konfigurace

Proměnná Hodnota Popis
HOST 192.168.1.4 Medicus Firebird server
DB_PATH c:\Medicus 3\data\MEDICUS.FDB Cesta k Firebird databázi
PFX_PATH certificates/picka.pfx Klientský certifikát pro mTLS
PFX_PASSWORD Heslo k PFX souboru
ENV prod Prostředí VZP (prod / simu)
MySQL host 192.168.1.76:3306 MySQL server, databáze medevio

Logování

Výstup jde současně do insurance_check.log i na konzoli. Formát:

2026-01-26 08:15:23 [INFO] Loaded 1620 registered patients
2026-01-26 08:15:23 [INFO] Incremental run: 1620 patients to check today
2026-01-26 08:15:25 [INFO] [1/1620] Checking Novák Jan (1234567890)
2026-01-26 08:15:26 [INFO]    ✔ OK (VZP)

Skript 2: Ověření proti medicus (report)

Soubor: 10 Ověření proti medicus.py

Porovná registrované pacienty v Medicus s posledním zaznamenaným pojistným stavem v MySQL. Pacienty s neaktivním pojištěním (stav != "1") vypíše do PDF reportu včetně přesného data zlomu pojištění.

Postup

  1. Načte registrované pacienty z Medicus
  2. Z MySQL vezme poslední stav pojištění pro každé RC (pomocí ROW_NUMBER() OVER PARTITION BY rc ORDER BY k_datu DESC)
  3. Vybere "podezřelé" — registrovaní v Medicus, ale stav != "1"
  4. Pro každého podezřelého provede binární hledání data zlomu:
    • hledá mezi MAX(k_datu WHERE stav='1') a dneškem
    • výsledek: insured_to (poslední den pojištění) a uninsured_from (první den bez pojištění)
  5. Vygeneruje HTML přes Jinja2 šablonu a převede na PDF přes WeasyPrint
  6. PDF otevře automaticky v systémovém prohlížeči

Šablona a výstup

  • Šablona: Templates/vzp_console_report.html
  • Fonty: Templates/fonts/DejaVuSans*.ttf
  • Výstup: Output/kontrola_pojisteni_YYYY-MM-DD_HH-MM-SS.pdf

Databáze

Tabulka vzp_stav_pojisteni (MySQL, medevio)

Sloupec Typ Popis
id INT AUTO_INCREMENT Primární klíč
rc VARCHAR(20) Rodné číslo pacienta
prijmeni VARCHAR(100) Příjmení
jmeno VARCHAR(100) Jméno
k_datu DATE Datum, ke kterému byl stav zjišťován
stav VARCHAR(10) "1" = pojištěn, ostatní = problém
kod_pojistovny VARCHAR(10) Kód pojišťovny dle VZP odpovědi
nazev_pojistovny VARCHAR(100) Název pojišťovny
pojisteni_kod VARCHAR(20) Kód druhu pojištění
stav_vyrizeni INT stavVyrizeniPozadavku ze SOAP odpovědi
response_xml MEDIUMTEXT Celá SOAP XML odpověď od VZP
created_at TIMESTAMP Čas vložení záznamu

Indexy: idx_rc (rc), idx_rc_k_datu (rc, k_datu), idx_rc_stav (rc, stav)

Klíčové SQL dotazy skriptů

-- Inkrementální filtr (skript 1)
SELECT MAX(k_datu) AS last_check FROM vzp_stav_pojisteni WHERE rc = ?

-- Poslední stav každého pacienta (skript 2)
SELECT rc, stav FROM (
    SELECT rc, stav,
           ROW_NUMBER() OVER (PARTITION BY rc ORDER BY k_datu DESC) AS rn
    FROM vzp_stav_pojisteni
) t WHERE rn = 1

-- Poslední den aktivního pojištění (pro binární hledání)
SELECT MAX(k_datu) AS last_insured
FROM vzp_stav_pojisteni WHERE rc = ? AND stav = '1'

VZP B2B API

Třída VZPB2BClient

Autentizace: mTLS — klientský PFX certifikát přes requests_pkcs12.Pkcs12Adapter

Metody:

Metoda SOAP služba Popis
stav_pojisteni(rc, k_datu) stavPojisteniB2B Ověří pojistný stav pacienta k datu
parse_stav_pojisteni(xml) Parsuje XML odpověď na dict
over_prukaz_pojistence(cislo, k_datu) OverPrukazPojistenceB2B Ověří průkaz pojištěnce (EHIC)

Prostředí:

ENV URL
prod https://prod.b2b.vzp.cz/B2BProxy/HttpProxy/stavPojisteniB2B
simu https://simu.b2b.vzp.cz/B2BProxy/HttpProxy/SIMUstavPojisteniB2B

Návratová struktura parse_stav_pojisteni():

{
    "stavVyrizeni":   int,        # stavVyrizeniPozadavku ze SOAP
    "stav":           str,        # "1" = pojištěn
    "kodPojistovny":  str,        # např. "111"
    "nazevPojistovny": str,       # např. "VZP"
    "pojisteniKod":   str
}

Medicus DB

Třída MedicusDB

Připojení: Firebird (fdb), 192.168.1.4, charset WIN1250, user SYSDBA.

Metoda get_active_registered_patients() — vrací pacienty splňující:

  • registr.datum_zruseni IS NULL — registrace není zrušená
  • registr.priznak IN ('A','D','V') — aktivní typy registrace
  • kar.rodcis IS NOT NULL AND kar.rodcis <> '' — má rodné číslo
  • kar.vyrazen <> 'A' — pacient není vyřazen

Kapacitní odhad

Parametr Hodnota
Počet pacientů ~1 600
Velikost XML odpovědi ~5001 500 B
Přírůstek dat ~1,6 MB/den
Přírůstek řádků ~1 600/den
Roční objem ~580 MB / ~580 000 řádků
Limit MEDIUMTEXT 16 MB/řádek — bez problémů

Spuštění

# 1. Denní sběr dat (ideálně naplánovat přes Task Scheduler)
python "10 FinalSaveInsuranceStatusScript(R).py"

# 2. Vygenerování PDF reportu (na vyžádání)
python "10 Ověření proti medicus.py"