notebookVB
This commit is contained in:
180
05 Kontrola pojištěnců/10 Čti OZP.py
Normal file
180
05 Kontrola pojištěnců/10 Čti OZP.py
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from blake3 import blake3
|
||||||
|
import pymysql
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# VÝVOJOVÝ PŘEPÍNAČ
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
RESET_DB = True # !!! POZOR: smaže kapitace a pojištěnce !!!
|
||||||
|
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# KONFIGURACE
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
BASE_PATH = Path(
|
||||||
|
r"U:\Dropbox\Ordinace\Dokumentace_ke_zpracování\Výpis pojištěnců"
|
||||||
|
)
|
||||||
|
|
||||||
|
DB_CONFIG = {
|
||||||
|
"host": "192.168.1.76",
|
||||||
|
"port": 3307,
|
||||||
|
"user": "root",
|
||||||
|
"password": "Vlado9674+",
|
||||||
|
"database": "ordinace",
|
||||||
|
"charset": "utf8mb4",
|
||||||
|
"autocommit": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# DB POMOCNÉ FUNKCE
|
||||||
|
# =========================
|
||||||
|
def reset_kapitace_tables(conn):
|
||||||
|
print("!!! RESET_DB=True – mažu data kapitace !!!")
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# kvůli FK
|
||||||
|
cur.execute("SET FOREIGN_KEY_CHECKS = 0")
|
||||||
|
|
||||||
|
cur.execute("TRUNCATE TABLE zp_kapitace_pojistenec")
|
||||||
|
cur.execute("TRUNCATE TABLE zp_kapitace_header")
|
||||||
|
|
||||||
|
cur.execute("SET FOREIGN_KEY_CHECKS = 1")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
print("✔ Kapitace resetována")
|
||||||
|
|
||||||
|
def get_conn():
|
||||||
|
return pymysql.connect(**DB_CONFIG)
|
||||||
|
|
||||||
|
def blake_exists(cur, blake):
|
||||||
|
cur.execute(
|
||||||
|
"SELECT id FROM zp_kapitace_header WHERE file_blake3 = %s",
|
||||||
|
(blake,),
|
||||||
|
)
|
||||||
|
return cur.fetchone()
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# PARSERY
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def parse_header(line: str):
|
||||||
|
return {
|
||||||
|
"icp_lekar": line[1:9].strip(),
|
||||||
|
"pocet_pojistencu": int(line[9:14]),
|
||||||
|
"rok": 2000 + int(line[14:16]),
|
||||||
|
"mesic": int(line[16:18]),
|
||||||
|
"den": int(line[18:20]),
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse_pojistenec(line: str):
|
||||||
|
return {
|
||||||
|
"poradi_radku": int(line[1:5]),
|
||||||
|
"vekova_skupina": int(line[5:7]),
|
||||||
|
"prijmeni": line[7:37].strip(),
|
||||||
|
"jmeno": line[37:61].strip(),
|
||||||
|
"cislo_pojistence": line[61:71].strip(),
|
||||||
|
"kapitace_od": date(
|
||||||
|
int(line[75:79]),
|
||||||
|
int(line[73:75]),
|
||||||
|
int(line[71:73]),
|
||||||
|
),
|
||||||
|
"zp_kod": line[79:82].strip(),
|
||||||
|
}
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# HLAVNÍ IMPORT
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def import_file(path: Path):
|
||||||
|
raw = path.read_bytes()
|
||||||
|
blake = blake3(raw).hexdigest()
|
||||||
|
|
||||||
|
text = raw.decode("cp852")
|
||||||
|
lines = text.splitlines()
|
||||||
|
|
||||||
|
with get_conn() as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
if blake_exists(cur, blake):
|
||||||
|
print(f"SKIP {path.name} (už existuje)")
|
||||||
|
return
|
||||||
|
|
||||||
|
# ---- HEADER ----
|
||||||
|
h = parse_header(lines[0])
|
||||||
|
snapshot_date = date(h["rok"], h["mesic"], h["den"])
|
||||||
|
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO zp_kapitace_header
|
||||||
|
(source_file, zp_kod, icp_lekar, pocet_pojistencu,
|
||||||
|
rok, mesic, den, snapshot_date,
|
||||||
|
file_blake3, file_content, file_size, file_lines)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
path.name,
|
||||||
|
path.name[1:4], # xxx ze jména Fxxx...
|
||||||
|
h["icp_lekar"],
|
||||||
|
h["pocet_pojistencu"],
|
||||||
|
h["rok"],
|
||||||
|
h["mesic"],
|
||||||
|
h["den"],
|
||||||
|
snapshot_date,
|
||||||
|
blake,
|
||||||
|
text,
|
||||||
|
len(raw),
|
||||||
|
len(lines),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
header_id = cur.lastrowid
|
||||||
|
|
||||||
|
# ---- POJISTENCI ----
|
||||||
|
for line in lines[1:]:
|
||||||
|
if not line.startswith("I"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
p = parse_pojistenec(line)
|
||||||
|
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO zp_kapitace_pojistenec
|
||||||
|
(header_id, poradi_radku, vekova_skupina,
|
||||||
|
prijmeni, jmeno, cislo_pojistence,
|
||||||
|
kapitace_od, zp_kod)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
header_id,
|
||||||
|
p["poradi_radku"],
|
||||||
|
p["vekova_skupina"],
|
||||||
|
p["prijmeni"],
|
||||||
|
p["jmeno"],
|
||||||
|
p["cislo_pojistence"],
|
||||||
|
p["kapitace_od"],
|
||||||
|
p["zp_kod"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
print(f"IMPORTED {path.name}")
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# RUN
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with get_conn() as conn:
|
||||||
|
if RESET_DB:
|
||||||
|
reset_kapitace_tables(conn)
|
||||||
|
|
||||||
|
for f in sorted(BASE_PATH.glob("F*.???")):
|
||||||
|
import_file(f)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
47
05 Kontrola pojištěnců/20 Kapdetais.py
Normal file
47
05 Kontrola pojištěnců/20 Kapdetais.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
from knihovny.medicus_db import MedicusDB # nebo odkud třídu importuješ
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
poj = input("Zadej kód pojišťovny (např. 207): ").strip()
|
||||||
|
|
||||||
|
db = MedicusDB(
|
||||||
|
host="192.168.1.4",
|
||||||
|
db_path=r"z:\medicus 3\data\medicus.fdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
fak.id,
|
||||||
|
fak.cisfak,
|
||||||
|
fak.poj,
|
||||||
|
fak.kapdetail
|
||||||
|
FROM fak
|
||||||
|
WHERE fak.poj = ?
|
||||||
|
AND fak.kapdetail IS NOT NULL
|
||||||
|
AND fak.kapdetail <> ''
|
||||||
|
ORDER BY fak.cisfak DESC
|
||||||
|
ROWS 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
rows = db.query_dict(sql, (poj,))
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
print(f"❌ Nenalezena žádná faktura s kapdetails pro pojišťovnu {poj}")
|
||||||
|
return
|
||||||
|
|
||||||
|
r = rows[0]
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"FAKTURA ID : {r['id']}")
|
||||||
|
print(f"ČÍSLO FAKTURY: {r['cisfak']}")
|
||||||
|
print(f"POJIŠŤOVNA : {r['poj']}")
|
||||||
|
print("-" * 80)
|
||||||
|
print("KAPDETAILS:")
|
||||||
|
print(r["kapdetail"])
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
234
05 Kontrola pojištěnců/30 Porovnani kapitace.py
Normal file
234
05 Kontrola pojištěnců/30 Porovnani kapitace.py
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Dict, Set
|
||||||
|
|
||||||
|
import pymysql
|
||||||
|
from knihovny.medicus_db import MedicusDB
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# KONFIGURACE
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# --- Firebird / Medicus ---
|
||||||
|
FIREBIRD_HOST = "192.168.1.4"
|
||||||
|
FIREBIRD_DB = r"Z:\medicus 3\data\medicus.fdb"
|
||||||
|
FIREBIRD_USER = "SYSDBA"
|
||||||
|
FIREBIRD_PASS = "masterkey"
|
||||||
|
FIREBIRD_CHARSET = "WIN1250"
|
||||||
|
|
||||||
|
# --- MySQL / Kapitace ---
|
||||||
|
MYSQL_CFG = {
|
||||||
|
"host": "192.168.1.76",
|
||||||
|
"port": 3307,
|
||||||
|
"user": "root",
|
||||||
|
"password": "Vlado9674+",
|
||||||
|
"database": "ordinace",
|
||||||
|
"charset": "utf8mb4",
|
||||||
|
"autocommit": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
MYSQL_TABLE_HEADER = "zp_kapitace_header"
|
||||||
|
MYSQL_TABLE_PAC = "zp_kapitace_pojistenec"
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# HELPERY
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
_rc_re = re.compile(r"\D+")
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_rc(value: str) -> str:
|
||||||
|
"""Rodné číslo / číslo pojištěnce → jen číslice."""
|
||||||
|
if not value:
|
||||||
|
return ""
|
||||||
|
return _rc_re.sub("", str(value))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_kapdetail_idpacs(kapdetail: str) -> List[int]:
|
||||||
|
"""
|
||||||
|
KAPDETAIL:
|
||||||
|
<něco>=SOUHRN;idpac;vek|castka;idpac;vek|castka;...
|
||||||
|
|
||||||
|
Vrací seznam idpac.
|
||||||
|
"""
|
||||||
|
if not kapdetail:
|
||||||
|
return []
|
||||||
|
|
||||||
|
s = kapdetail.strip()
|
||||||
|
|
||||||
|
if "=" in s:
|
||||||
|
s = s.split("=", 1)[1]
|
||||||
|
|
||||||
|
parts = [p.strip() for p in s.split(";") if p.strip()]
|
||||||
|
|
||||||
|
if not parts:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# první položka je souhrn (není idpac)
|
||||||
|
if not parts[0].isdigit():
|
||||||
|
parts = parts[1:]
|
||||||
|
|
||||||
|
idpacs: List[int] = []
|
||||||
|
|
||||||
|
# idpac je vždy na sudém indexu (0,2,4,...)
|
||||||
|
for i in range(0, len(parts), 2):
|
||||||
|
if parts[i].isdigit():
|
||||||
|
idpacs.append(int(parts[i]))
|
||||||
|
|
||||||
|
return idpacs
|
||||||
|
|
||||||
|
|
||||||
|
def chunk_list(lst: List[int], size: int = 500) -> List[List[int]]:
|
||||||
|
return [lst[i:i + size] for i in range(0, len(lst), size)]
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# FIREBIRD – DATA Z MEDICUSU
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def get_latest_fak_for_poj(db: MedicusDB, poj: str) -> Dict:
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
fak.id,
|
||||||
|
fak.cisfak,
|
||||||
|
fak.poj,
|
||||||
|
fak.kapdetail
|
||||||
|
FROM fak
|
||||||
|
WHERE fak.poj = ?
|
||||||
|
AND fak.kapdetail IS NOT NULL
|
||||||
|
AND fak.kapdetail <> ''
|
||||||
|
ORDER BY fak.cisfak DESC
|
||||||
|
ROWS 1
|
||||||
|
"""
|
||||||
|
rows = db.query_dict(sql, (poj,))
|
||||||
|
return rows[0] if rows else {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_rodcis_for_idpacs(db: MedicusDB, idpacs: List[int]) -> Dict[int, str]:
|
||||||
|
"""
|
||||||
|
Vrátí mapu: idpac → rodcis
|
||||||
|
"""
|
||||||
|
result: Dict[int, str] = {}
|
||||||
|
|
||||||
|
if not idpacs:
|
||||||
|
return result
|
||||||
|
|
||||||
|
for batch in chunk_list(idpacs):
|
||||||
|
placeholders = ",".join("?" for _ in batch)
|
||||||
|
sql = f"""
|
||||||
|
SELECT
|
||||||
|
kar.idpac,
|
||||||
|
kar.rodcis
|
||||||
|
FROM kar
|
||||||
|
WHERE kar.idpac IN ({placeholders})
|
||||||
|
AND kar.rodcis IS NOT NULL
|
||||||
|
AND kar.rodcis <> ''
|
||||||
|
AND (kar.vyrazen IS NULL OR kar.vyrazen <> 'A')
|
||||||
|
"""
|
||||||
|
rows = db.query(sql, tuple(batch))
|
||||||
|
for idpac, rodcis in rows:
|
||||||
|
result[int(idpac)] = str(rodcis)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# MYSQL – KAPITACE ZP
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def get_mysql_kapitace_rc(zp_kod: str) -> Set[str]:
|
||||||
|
sql = f"""
|
||||||
|
SELECT p.cislo_pojistence
|
||||||
|
FROM {MYSQL_TABLE_PAC} p
|
||||||
|
JOIN {MYSQL_TABLE_HEADER} h ON h.id = p.header_id
|
||||||
|
WHERE h.zp_kod = %s
|
||||||
|
AND h.snapshot_date = (
|
||||||
|
SELECT MAX(h2.snapshot_date)
|
||||||
|
FROM {MYSQL_TABLE_HEADER} h2
|
||||||
|
WHERE h2.zp_kod = %s
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pymysql.connect(**MYSQL_CFG) as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(sql, (zp_kod, zp_kod))
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
return {
|
||||||
|
normalize_rc(r[0])
|
||||||
|
for r in rows
|
||||||
|
if normalize_rc(r[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# MAIN
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
poj = input("Zadej kód pojišťovny (např. 207): ").strip()
|
||||||
|
|
||||||
|
# --- Medicus ---
|
||||||
|
mdb = MedicusDB(
|
||||||
|
host=FIREBIRD_HOST,
|
||||||
|
db_path=FIREBIRD_DB,
|
||||||
|
user=FIREBIRD_USER,
|
||||||
|
password=FIREBIRD_PASS,
|
||||||
|
charset=FIREBIRD_CHARSET,
|
||||||
|
)
|
||||||
|
|
||||||
|
fak = get_latest_fak_for_poj(mdb, poj)
|
||||||
|
if not fak:
|
||||||
|
print(f"❌ Nenalezena žádná kapitační faktura pro pojišťovnu {poj}")
|
||||||
|
mdb.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\nNalezena faktura:")
|
||||||
|
print(f" ID : {fak['id']}")
|
||||||
|
print(f" CISFAK : {fak['cisfak']}")
|
||||||
|
print(f" POJ : {fak['poj']}")
|
||||||
|
|
||||||
|
idpacs = parse_kapdetail_idpacs(fak["kapdetail"])
|
||||||
|
print(f"\nKAPDETAIL → idpac celkem: {len(idpacs)}")
|
||||||
|
|
||||||
|
idpac_to_rc = get_rodcis_for_idpacs(mdb, idpacs)
|
||||||
|
mdb.close()
|
||||||
|
|
||||||
|
medicus_rc = {
|
||||||
|
normalize_rc(rc)
|
||||||
|
for rc in idpac_to_rc.values()
|
||||||
|
if normalize_rc(rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"Medicus (KAR.RODCIS): {len(medicus_rc)}")
|
||||||
|
|
||||||
|
# --- MySQL ---
|
||||||
|
mysql_rc = get_mysql_kapitace_rc(poj)
|
||||||
|
print(f"MySQL kapitace ZP: {len(mysql_rc)}")
|
||||||
|
|
||||||
|
# --- Porovnání ---
|
||||||
|
both = medicus_rc & mysql_rc
|
||||||
|
only_medicus = medicus_rc - mysql_rc
|
||||||
|
only_mysql = mysql_rc - medicus_rc
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print(f"✅ V obou (OK): {len(both)}")
|
||||||
|
print(f"❌ Jen v Medicusu: {len(only_medicus)}")
|
||||||
|
print(f"❌ Jen v MySQL (kapitace): {len(only_mysql)}")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
if only_medicus:
|
||||||
|
print("\n❌ Jen v Medicusu (fakturováno, ale není v kapitaci ZP):")
|
||||||
|
for rc in sorted(only_medicus):
|
||||||
|
print(" ", rc)
|
||||||
|
|
||||||
|
if only_mysql:
|
||||||
|
print("\n❌ Jen v MySQL (v kapitaci ZP, ale není ve faktuře Medicusu):")
|
||||||
|
for rc in sorted(only_mysql):
|
||||||
|
print(" ", rc)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -13,6 +13,21 @@ class MedicusDB:
|
|||||||
)
|
)
|
||||||
self.cur = self.conn.cursor()
|
self.cur = self.conn.cursor()
|
||||||
|
|
||||||
|
def get_fak_kapitace(self, as_dict=False):
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
fak.id,
|
||||||
|
fak.cisfak,
|
||||||
|
fak.poj,
|
||||||
|
fak.kapdetail
|
||||||
|
FROM fak
|
||||||
|
WHERE fak.kapdetail IS NOT NULL
|
||||||
|
AND fak.kapdetail <> ''
|
||||||
|
"""
|
||||||
|
if as_dict:
|
||||||
|
return self.query_dict(sql)
|
||||||
|
return self.query(sql)
|
||||||
|
|
||||||
def query(self, sql, params=None):
|
def query(self, sql, params=None):
|
||||||
self.cur.execute(sql, params or ())
|
self.cur.execute(sql, params or ())
|
||||||
return self.cur.fetchall()
|
return self.cur.fetchall()
|
||||||
|
|||||||
Reference in New Issue
Block a user