# functions.py # pip install requests_pkcs12 pymysql from __future__ import annotations import os from datetime import date from pprint import pprint import xml.etree.ElementTree as ET import requests from requests_pkcs12 import Pkcs12Adapter import pymysql from pymysql.cursors import DictCursor import fdb import socket def get_medicus_connection(): """ Attempt to create a Firebird connection to the Medicus database. Returns: fdb.Connection object on success None on failure """ if socket.gethostname().strip()=="NTBVBHP470G10": MEDICUS_CFG = dict( dsn=r"192.168.1.4:z:\medicus 3\data\medicus.fdb", user="SYSDBA", password="masterkey", charset="win1250", ) elif: try: return fdb.connect(**MEDICUS_CFG) except fdb.fbcore.DatabaseError as e: print(f"Medicus DB connection failed: {e}") return None # -------- MySQL (Medevio, etc.) ------- MYSQL_CFG = dict( host="192.168.1.76", port=3307, user="root", password="Vlado9674+", database="medevio", cursorclass=DictCursor, autocommit=True, # or False if you prefer manual commit ) def get_mysql_connection(): """ Return a PyMySQL connection or None if the connection fails. """ try: return pymysql.connect(**MYSQL_CFG) except pymysql.MySQLError as e: print(f"MySQL connection failed: {e}") return None # ======== CONFIG (env overrides allowed) ======== PFX_PATH = os.getenv("VZP_PFX_PATH", r"mbcert.pfx") PFX_PASS = os.getenv("VZP_PFX_PASS", "Vlado7309208104++") VERIFY = os.getenv("VZP_CA_VERIFY", "true").lower() != "false" # set to path or "false" to disable EP_STAV = "https://prod.b2b.vzp.cz/B2BProxy/HttpProxy/stavPojisteniB2B" SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/" NS_STAV = "http://xmlns.gemsystem.cz/stavPojisteniB2B" MYSQL_CFG = { "host": os.getenv("MYSQL_HOST", "192.168.1.76"), "port": int(os.getenv("MYSQL_PORT", "3307")), "user": os.getenv("MYSQL_USER", "root"), "password": os.getenv("MYSQL_PASSWORD", "Vlado9674+"), "database": os.getenv("MYSQL_DB", "medevio"), "cursorclass": DictCursor, "autocommit": False, } # ======== HELPERS ======== def normalize_rc(rc: str) -> str: """Return rodné číslo without slash/spaces.""" return rc.replace("/", "").replace(" ", "").strip() def to_int_or_none(val): if val is None: return None s = str(val).strip() return int(s) if s.isdigit() else None def _session(): s = requests.Session() s.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_PATH, pkcs12_password=PFX_PASS)) return s def post_soap(endpoint: str, inner_xml: str) -> str: """Wrap body in SOAP 1.1 envelope and POST with mTLS.""" envelope = f''' {inner_xml} ''' r = _session().post( endpoint, data=envelope.encode("utf-8"), headers={"Content-Type": "text/xml; charset=utf-8", "SOAPAction": "process"}, timeout=30, verify=VERIFY, ) # You may log r.status_code if needed. return r.text def parse_stav(xml_text: str) -> dict: """Parse StavPojisteniB2B response → dict with keys: 'stav','kodPojistovny','nazevPojistovny','pojisteniKod','stavVyrizeniPozadavku'.""" NS = {"soap": SOAP_NS, "s": NS_STAV} root = ET.fromstring(xml_text) out = {"stav": None, "kodPojistovny": None, "nazevPojistovny": None, "pojisteniKod": None, "stavVyrizeniPozadavku": None} node = root.find(".//s:stavPojisteni", NS) if node is not None: for tag in ("stav", "kodPojistovny", "nazevPojistovny", "pojisteniKod"): el = node.find(f"s:{tag}", NS) out[tag] = el.text.strip() if (el is not None and el.text) else None st = root.find(".//s:stavVyrizeniPozadavku", NS) out["stavVyrizeniPozadavku"] = st.text.strip() if (st is not None and st.text) else None return out def save_stav_pojisteni(rc: str, k_datu: str, parsed: dict, response_xml: str) -> None: """Insert one log row into medevio.vzp_stav_pojisteni and print what is being saved.""" payload = { "rc": normalize_rc(rc), "k_datu": k_datu, "stav": to_int_or_none(parsed.get("stav")), # 'X' -> None "kod_pojistovny": parsed.get("kodPojistovny"), "nazev_pojistovny": parsed.get("nazevPojistovny"), "pojisteni_kod": parsed.get("pojisteniKod"), "stav_vyrizeni": to_int_or_none(parsed.get("stavVyrizeniPozadavku")), "response_xml": response_xml, } print("\n=== vzp_stav_pojisteni: will insert ===") pprint(payload) sql = """ INSERT INTO vzp_stav_pojisteni (rc, k_datu, stav, kod_pojistovny, nazev_pojistovny, pojisteni_kod, stav_vyrizeni, response_xml) VALUES (%(rc)s, %(k_datu)s, %(stav)s, %(kod_pojistovny)s, %(nazev_pojistovny)s, %(pojisteni_kod)s, %(stav_vyrizeni)s, %(response_xml)s) """ conn = pymysql.connect(**MYSQL_CFG) try: with conn.cursor() as cur: cur.execute(sql, payload) conn.commit() finally: conn.close() print("Inserted 1 row into vzp_stav_pojisteni.") # ======== PUBLIC API ======== def check_insurance(rc: str, mode: str | None = None, k_datu: str | None = None): """ Call VZP 'StavPojisteniB2B' for given RC and date. Returns (is_active, info_dict). - is_active: True iff info_dict['stav'] == '1' - info_dict: {'stav','kodPojistovny','nazevPojistovny','pojisteniKod','stavVyrizeniPozadavku'} If mode == 'nodb' (case-insensitive), DOES NOT write to DB. Otherwise logs into medevio.vzp_stav_pojisteni. """ rc_norm = normalize_rc(rc) kd = k_datu or date.today().isoformat() body = f""" {rc_norm} {kd} """.strip() xml = post_soap(EP_STAV, body) info = parse_stav(xml) is_active = (info.get("stav") == "1") if not (mode and mode.lower() == "nodb"): save_stav_pojisteni(rc_norm, kd, info, xml) return is_active, info