Files
ordinaceprojekt/Insurance/FinalReconcilliation/report_tracking.py
T
Vladimir Buzalka 9b6f89f437 notebookvb
2026-06-16 10:21:19 +02:00

211 lines
8.2 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
report_tracking.py
==================
Excel report nad MongoDB `ordinace.registrovani_tracking`.
Pro každého pacienta zobrazí:
jméno, datum narození, rodné číslo, pojišťovnu, stav a důvod (kdo + od kdy).
Identifikační údaje (jméno, datum narození, pojišťovna) se berou AUTORITATIVNĚ
z Medicus Firebird tabulky `kar` (přes Knihovny.medicus_db.get_medicus_connection).
Stav a důvod (kategorie, flag, flag_duvod, praktik kdo/od kdy) z Mongo trackingu.
Výstup: report_registrovani_<vychozi_datum>.xlsx v tomto adresáři.
"""
import sys
from pathlib import Path
from datetime import date
from collections import defaultdict
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
import pymongo
from Knihovny.medicus_db import get_medicus_connection
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
# ── Konfigurace ────────────────────────────────────────────────────────────────
MONGO_URI = "mongodb://192.168.1.76:27017"
MONGO_DB = "ordinace"
MONGO_COLL = "registrovani_tracking"
POJ_NAZVY = {
"111": "VZP", "201": "VoZP", "205": "ČPZP", "207": "OZP",
"209": "ZPŠ", "211": "ZPMV ČR", "213": "RBP",
}
# Barvy podle kategorie
BLUE_HEADER = "1F497D"
WHITE = "FFFFFF"
BARVA_KAT = {
"OK_BUZALKOVA": "EBF1DE", # zelená
"JINY_PRAKTIK": "FCE4D6", # červená
"BEZ_PRAKTIKA_VZP": "FFF2CC", # žlutá
"BEZ_ZAZNAMU_VZP": "DCE6F1", # modrá
}
STAV_TEXT = {
"OK_BUZALKOVA": "V souboru",
"JINY_PRAKTIK": "NEBYL v souboru",
"BEZ_PRAKTIKA_VZP": "NEBYL v souboru",
"BEZ_ZAZNAMU_VZP": "NEBYL v souboru",
}
def chunked(seq, n):
for i in range(0, len(seq), n):
yield seq[i:i + n]
def nacti_kar(conn, rcs):
"""Vrátí {rc: {prijmeni, jmeno, datnar, poj}} z Medicus kar."""
out = {}
cur = conn.cursor()
for batch in chunked(rcs, 500): # Firebird IN má limit 1500 prvků
ph = ",".join("?" for _ in batch)
cur.execute(
f"SELECT TRIM(rodcis), TRIM(prijmeni), TRIM(jmeno), datnar, TRIM(poj) "
f"FROM kar WHERE rodcis IN ({ph})", batch)
for rc, prij, jm, datnar, poj in cur.fetchall():
out[(rc or "").strip()] = {
"prijmeni": prij, "jmeno": jm,
"datnar": datnar, "poj": (poj or "").strip(),
}
return out
def main():
client = pymongo.MongoClient(MONGO_URI, serverSelectionTimeoutMS=3000)
coll = client[MONGO_DB][MONGO_COLL]
docs = list(coll.find({}))
vychozi = docs[0].get("vychozi_datum", "snimek") if docs else "snimek"
rcs = [d["_id"] for d in docs]
print(f"Pacientů v trackingu: {len(rcs)}")
print("Načítám kar z Medicusu ...")
conn = get_medicus_connection()
kar = nacti_kar(conn, rcs)
conn.close()
print(f"Dohledáno v kar: {len(kar)}")
# ── Sestavení řádků ────────────────────────────────────────────────────────
rows = []
for d in docs:
rc = d["_id"]
a = d.get("aktualni", {})
k = kar.get(rc, {})
prijmeni = k.get("prijmeni") or d.get("prijmeni") or ""
jmeno = k.get("jmeno") or d.get("jmeno") or ""
datnar = k.get("datnar")
poj_kod = k.get("poj") or (d.get("pojistovna") or {}).get("kod") or ""
kat = a.get("kategorie", "")
rows.append({
"prijmeni": prijmeni,
"jmeno": jmeno,
"datnar": datnar.strftime("%d.%m.%Y") if datnar else "",
"rc": rc,
"poj": f"{poj_kod} {POJ_NAZVY.get(poj_kod, '')}".strip(),
"stav": STAV_TEXT.get(kat, kat),
"kategorie": a.get("kategorie_popis", ""),
"duvod": a.get("flag_duvod", ""),
"kat_kod": kat,
})
# Řazení: nejdřív flagnutí (mimo soubor), pak podle příjmení
rows.sort(key=lambda r: (r["kat_kod"] == "OK_BUZALKOVA", r["prijmeni"], r["jmeno"]))
# ── Excel ──────────────────────────────────────────────────────────────────
wb = Workbook()
# List 1: Přehled
ws_p = wb.active
ws_p.title = "Přehled"
ws_p.column_dimensions["A"].width = 34
ws_p.column_dimensions["B"].width = 14
ws_p.merge_cells("A1:B1")
t = ws_p["A1"]
t.value = f"Registrovaní pacienti k {vychozi} — ověření praktika u VZP"
t.font = Font(name="Arial", bold=True, size=13, color=WHITE)
t.fill = PatternFill("solid", fgColor=BLUE_HEADER)
t.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
ws_p.row_dimensions[1].height = 34
ws_p["A2"] = f"Vygenerováno: {date.today().strftime('%d.%m.%Y')}"
ws_p["A2"].font = Font(name="Arial", italic=True, size=9, color="595959")
counts = defaultdict(int)
for r in rows:
counts[r["kat_kod"]] += 1
ws_p.cell(row=4, column=1, value="Kategorie / stav").font = Font(bold=True)
ws_p.cell(row=4, column=2, value="Počet").font = Font(bold=True)
poradi = ["OK_BUZALKOVA", "JINY_PRAKTIK", "BEZ_PRAKTIKA_VZP", "BEZ_ZAZNAMU_VZP"]
KAT_POPIS = {
"OK_BUZALKOVA": "V souboru (praktik Buzalková)",
"JINY_PRAKTIK": "Mimo soubor — jiný praktik",
"BEZ_PRAKTIKA_VZP": "Mimo soubor — bez praktika u VZP",
"BEZ_ZAZNAMU_VZP": "Mimo soubor — bez záznamu u VZP",
}
for i, kat in enumerate(poradi):
r = 5 + i
c1 = ws_p.cell(row=r, column=1, value=KAT_POPIS[kat])
c2 = ws_p.cell(row=r, column=2, value=counts[kat])
fill = PatternFill("solid", fgColor=BARVA_KAT[kat])
c1.fill = fill; c2.fill = fill
c1.font = Font(name="Arial", size=10)
ws_p.cell(row=9, column=1, value="CELKEM").font = Font(bold=True)
ws_p.cell(row=9, column=2, value=len(rows)).font = Font(bold=True)
mimo = len(rows) - counts["OK_BUZALKOVA"]
ws_p.cell(row=10, column=1, value="z toho NEBYL v zakoupeném souboru").font = Font(bold=True, color="C00000")
ws_p.cell(row=10, column=2, value=mimo).font = Font(bold=True, color="C00000")
# List 2: Pacienti
ws = wb.create_sheet("Pacienti")
COLS = [
("Příjmení", 20), ("Jméno", 14), ("Datum narození", 14),
("Rodné číslo", 14), ("Pojišťovna", 14), ("Stav", 16),
("Kategorie", 30), ("Důvod (kdo / od kdy)", 52),
]
for ci, (h, w) in enumerate(COLS, 1):
c = ws.cell(row=1, column=ci, value=h)
c.font = Font(name="Arial", bold=True, color=WHITE, size=10)
c.fill = PatternFill("solid", fgColor=BLUE_HEADER)
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
ws.column_dimensions[get_column_letter(ci)].width = w
ws.row_dimensions[1].height = 30
ws.freeze_panes = "A2"
thin = Side(style="thin", color="D9D9D9")
border = Border(left=thin, right=thin, top=thin, bottom=thin)
for ri, r in enumerate(rows, 2):
bg = BARVA_KAT.get(r["kat_kod"], "FFFFFF")
data = [r["prijmeni"], r["jmeno"], r["datnar"], r["rc"], r["poj"],
r["stav"], r["kategorie"], r["duvod"]]
for ci, val in enumerate(data, 1):
c = ws.cell(row=ri, column=ci, value=val)
c.font = Font(name="Arial", size=9)
c.fill = PatternFill("solid", fgColor=bg)
c.border = border
c.alignment = Alignment(vertical="center", wrap_text=(ci == 8))
if ci == 6 and r["kat_kod"] != "OK_BUZALKOVA":
c.font = Font(name="Arial", size=9, bold=True, color="C00000")
ws.auto_filter.ref = f"A1:{get_column_letter(len(COLS))}{len(rows) + 1}"
out = Path(__file__).resolve().parent / f"report_registrovani_{vychozi}.xlsx"
wb.save(out)
print(f"\nUloženo: {out}")
print(f"Řádků: {len(rows)} | v souboru: {counts['OK_BUZALKOVA']} | mimo: {mimo}")
client.close()
if __name__ == "__main__":
main()