#!/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_.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()