notebookvb
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys as _sys
|
||||
_sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
_sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
||||
"""
|
||||
zadej_davku.py
|
||||
==============
|
||||
Odešle asynchronní požadavek na VZP B2B službu SeznamRegPojistencuB2B
|
||||
(seznam zakapitovaných/registrovaných pojištěnců za dané období).
|
||||
|
||||
Použití:
|
||||
python zadej_davku.py [mesic] [rok]
|
||||
python zadej_davku.py 2 2025 # únor 2025
|
||||
python zadej_davku.py # předchozí měsíc (výchozí)
|
||||
|
||||
Výstup:
|
||||
- korelační ID zprávy (pro pozdější spárování asynchronní odpovědi)
|
||||
- stavVyrizeniPozadavku=2 znamená "přijato, VZP zpracovává"
|
||||
- finální odpověď přijde asynchronně na AS2 endpoint partnera
|
||||
"""
|
||||
|
||||
import sys
|
||||
import uuid
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from datetime import date, timedelta
|
||||
|
||||
from requests_pkcs12 import Pkcs12Adapter
|
||||
import requests
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
# ── KONFIGURACE ───────────────────────────────────────────────────────────────
|
||||
|
||||
PFX_PATH = Path(__file__).resolve().parent.parent / "Certificates" / "picka.pfx"
|
||||
PFX_PASSWORD = "Vlado7309208104+"
|
||||
|
||||
ICZ = "09305000"
|
||||
ENV = "prod"
|
||||
|
||||
NS_VZP = "http://xmlns.gemsystem.cz/SeznamRegPojistencuB2B"
|
||||
NS_COMMON = "http://xmlns.gemsystem.cz/CommonB2B"
|
||||
NS_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
|
||||
ENDPOINT_SIMU = "https://simu.b2b.vzp.cz/B2BProxy/HttpProxy/SIMUSeznamRegPojistencuB2B?sluzba=SIMUSeznamRegPojistencuB2B"
|
||||
ENDPOINT_PROD = "https://prod.b2b.vzp.cz/B2BProxy/HttpProxy/SeznamRegPojistencuB2B"
|
||||
|
||||
# ── ARGUMENTY ────────────────────────────────────────────────────────────────
|
||||
|
||||
parser = argparse.ArgumentParser(description="Požadavek na seznam registrovaných pojištěnců VZP")
|
||||
parser.add_argument("mesic", nargs="?", type=int, help="Měsíc (1-12)")
|
||||
parser.add_argument("rok", nargs="?", type=int, help="Rok (např. 2025)")
|
||||
parser.add_argument("--simu", action="store_true", help="Použít simulační prostředí")
|
||||
parser.add_argument("--pdf", action="store_true", help="Výstup jako PDF (výchozí: text/plain)")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Výchozí: předchozí měsíc
|
||||
if args.mesic and args.rok:
|
||||
mesic, rok = args.mesic, args.rok
|
||||
else:
|
||||
prvni_tohoto = date.today().replace(day=1)
|
||||
predchozi = prvni_tohoto - timedelta(days=1)
|
||||
mesic, rok = predchozi.month, predchozi.year
|
||||
|
||||
format_vystupu = "application/pdf" if args.pdf else "text/plain"
|
||||
endpoint = ENDPOINT_SIMU if args.simu else ENDPOINT_PROD
|
||||
|
||||
# ── KONTROLY ─────────────────────────────────────────────────────────────────
|
||||
|
||||
if not PFX_PATH.exists():
|
||||
print(f"CHYBA: certifikát nenalezen: {PFX_PATH}")
|
||||
sys.exit(1)
|
||||
|
||||
if not (1 <= mesic <= 12):
|
||||
print(f"CHYBA: neplatný měsíc: {mesic}")
|
||||
sys.exit(1)
|
||||
|
||||
# ── SESTAVENÍ POŽADAVKU ───────────────────────────────────────────────────────
|
||||
|
||||
id_zpravy = uuid.uuid4().hex[:12].upper()
|
||||
|
||||
soap = f"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelope
|
||||
xmlns:soap="{NS_SOAP}"
|
||||
xmlns:vzp="{NS_VZP}"
|
||||
xmlns:com="{NS_COMMON}">
|
||||
|
||||
<soap:Header>
|
||||
<com:idZpravy>{id_zpravy}</com:idZpravy>
|
||||
<com:idSubjektu>
|
||||
<com:icz>{ICZ}</com:icz>
|
||||
</com:idSubjektu>
|
||||
</soap:Header>
|
||||
|
||||
<soap:Body>
|
||||
<vzp:seznamRegistrovanychPojistencuB2BPozadavek>
|
||||
<vzp:idZpravy>{id_zpravy}</vzp:idZpravy>
|
||||
<vzp:idSubjektu>{ICZ}</vzp:idSubjektu>
|
||||
<vzp:typSubjektu>zp</vzp:typSubjektu>
|
||||
<vzp:seznam>
|
||||
<vzp:obdobiDavky>
|
||||
<vzp:mesic>{mesic}</vzp:mesic>
|
||||
<vzp:rok>{rok}</vzp:rok>
|
||||
</vzp:obdobiDavky>
|
||||
<vzp:formatVystupu>{format_vystupu}</vzp:formatVystupu>
|
||||
</vzp:seznam>
|
||||
</vzp:seznamRegistrovanychPojistencuB2BPozadavek>
|
||||
</soap:Body>
|
||||
|
||||
</soap:Envelope>"""
|
||||
|
||||
# ── ODESLÁNÍ ─────────────────────────────────────────────────────────────────
|
||||
|
||||
print(f"Období: {mesic:02d}/{rok}")
|
||||
print(f"Formát: {format_vystupu}")
|
||||
print(f"Prostředí: {'SIMU' if args.simu else 'PROD'}")
|
||||
print(f"IČZ: {ICZ}")
|
||||
print(f"ID zprávy: {id_zpravy}")
|
||||
print(f"Endpoint: {endpoint}")
|
||||
print()
|
||||
|
||||
session = requests.Session()
|
||||
session.mount("https://", Pkcs12Adapter(
|
||||
pkcs12_filename=str(PFX_PATH),
|
||||
pkcs12_password=PFX_PASSWORD
|
||||
))
|
||||
|
||||
try:
|
||||
resp = session.post(
|
||||
endpoint,
|
||||
data=soap.encode("utf-8"),
|
||||
headers={"Content-Type": "text/xml; charset=utf-8", "SOAPAction": "process"},
|
||||
timeout=30
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
print(f"CHYBA při spojení: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"HTTP status: {resp.status_code}")
|
||||
print()
|
||||
|
||||
# ── PARSOVÁNÍ ODPOVĚDI ────────────────────────────────────────────────────────
|
||||
|
||||
if not resp.content:
|
||||
print("→ Požadavek přijat (prázdná odpověď = asynchronní služba).")
|
||||
print(f"→ VZP zpracuje a odešle výsledek na AS2 endpoint.")
|
||||
print(f"→ ID zprávy pro spárování: {id_zpravy}")
|
||||
else:
|
||||
try:
|
||||
root = ET.fromstring(resp.text)
|
||||
NS = {"soap": NS_SOAP, "vzp": NS_VZP}
|
||||
korelace = root.find(".//vzp:korelaceZpravy", NS)
|
||||
text_odp = root.find(".//vzp:textOdpovedi", NS)
|
||||
stav = root.find(".//vzp:stavVyrizeniPozadavku", NS)
|
||||
|
||||
print(f"Korelace zprávy: {korelace.text if korelace is not None else '–'}")
|
||||
print(f"Text odpovědi: {text_odp.text if text_odp is not None else '–'}")
|
||||
print(f"Stav vyřízení: {stav.text if stav is not None else '–'}")
|
||||
|
||||
if stav is not None and stav.text == "2":
|
||||
print()
|
||||
print("→ VZP zpracovává — finální odpověď přijde asynchronně na AS2 endpoint.")
|
||||
print(f"→ ID zprávy pro spárování: {id_zpravy}")
|
||||
|
||||
except ET.ParseError:
|
||||
print("Nepodařilo se parsovat XML odpověď:")
|
||||
print(resp.text)
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Přihlásí se na VZP Point a stáhne nové zprávy.
|
||||
Přihlásí se na VZP Point, stáhne nové zprávy a aktualizuje číselníky.
|
||||
|
||||
Kombinuje 01_prihlaseni.py + 03_stahuj_nove.py do jednoho spuštění.
|
||||
Kombinuje 01_prihlaseni.py + 03_stahuj_nove.py + 01_stahni_ciselniky.py.
|
||||
Přihlášení probíhá plně automaticky (Chrome auto-vybere certifikát).
|
||||
|
||||
POUŽITÍ:
|
||||
@@ -13,23 +13,29 @@ import sys
|
||||
import os
|
||||
|
||||
DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
CISELNIKY_SCRIPT = os.path.abspath(
|
||||
os.path.join(DIR, "..", "..", "..", "Recepty", "StahovánízVZPWithClaude", "01_stahni_ciselniky.py")
|
||||
)
|
||||
|
||||
|
||||
def run(script: str) -> None:
|
||||
result = subprocess.run(
|
||||
[sys.executable, os.path.join(DIR, script)],
|
||||
[sys.executable, script],
|
||||
check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise SystemExit(f"Skript {script} skončil s chybou (kód {result.returncode})")
|
||||
raise SystemExit(f"Skript {os.path.basename(script)} skončil s chybou (kód {result.returncode})")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("=== Přihlášení ===")
|
||||
run("01_prihlaseni.py")
|
||||
run(os.path.join(DIR, "01_prihlaseni.py"))
|
||||
|
||||
print("\n=== Stahování nových zpráv ===")
|
||||
run("03_stahuj_nove.py")
|
||||
run(os.path.join(DIR, "03_stahuj_nove.py"))
|
||||
|
||||
print("\n=== Stahování číselníků VZP ===")
|
||||
run(CISELNIKY_SCRIPT)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user