""" Report posledních receptů — export do Excelu. Soubor se ukládá do adresáře report/ s verzováním: report_predpisy_RRRR-MM-DD.xlsx report_predpisy_RRRR-MM-DD_v2.xlsx (pokud základní existuje) atd. Spuštění: python report/report_predpisy_excel.py """ from datetime import date, datetime from pathlib import Path import sys import pymysql import pymysql.cursors from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side from openpyxl.utils import get_column_letter if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(errors="replace") # ── Konfigurace ─────────────────────────────────────────────────────────────── DB = dict( host = "192.168.1.76", user = "root", password = "Vlado9674+", database = "medicus", charset = "utf8mb4", cursorclass = pymysql.cursors.DictCursor, ) LIMIT = 100 VYSTUP_DIR = Path(__file__).parent # adresář report/ # ── Barvy (stejné jako prehled_pacienta_excel.py) ──────────────────────────── C_HEADER_BG = "1F4E79" C_HEADER_FG = "FFFFFF" C_TITLE_BG = "2E75B6" C_TITLE_FG = "FFFFFF" C_INFO_BG = "DEEAF1" C_ROW_ODD = "FFFFFF" C_ROW_EVEN = "EBF3FB" C_NEVYZV_BG = "FCE4D6" C_BORDER = "B8CCE4" # ── Pomocné funkce stylování ───────────────────────────────────────────────── def thin_border(): s = Side(style="thin", color=C_BORDER) return Border(left=s, right=s, top=s, bottom=s) def fill(color): return PatternFill("solid", fgColor=color) def zapis_nadpis_sekce(ws, row, text, n_cols): ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=n_cols) cell = ws.cell(row=row, column=1, value=text) cell.font = Font(name="Arial", bold=True, size=11, color=C_TITLE_FG) cell.fill = fill(C_TITLE_BG) cell.alignment = Alignment(horizontal="left", vertical="center", indent=1) ws.row_dimensions[row].height = 22 return row + 1 def zapis_hlavicku(ws, row, hlavicka): for col, text in enumerate(hlavicka, 1): cell = ws.cell(row=row, column=col, value=text) cell.font = Font(name="Arial", bold=True, size=10, color=C_HEADER_FG) cell.fill = fill(C_HEADER_BG) cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True) cell.border = thin_border() ws.row_dimensions[row].height = 28 return row + 1 def zapis_radek(ws, row, hodnoty, highlight=False): bg = C_NEVYZV_BG if highlight else (C_ROW_EVEN if row % 2 == 0 else C_ROW_ODD) f = fill(bg) for col, val in enumerate(hodnoty, 1): cell = ws.cell(row=row, column=col, value=val) cell.font = Font(name="Arial", size=10) cell.fill = f cell.alignment = Alignment(vertical="center", wrap_text=True) cell.border = thin_border() ws.row_dimensions[row].height = 18 return row + 1 def autofit(ws, min_w=5, max_w=60, pad=2): col_widths = {} for row in ws.iter_rows(): for cell in row: if cell.value is None: continue factor = 1.15 if (cell.font and cell.font.bold) else 1.0 w = len(str(cell.value)) * factor + pad c = get_column_letter(cell.column) col_widths[c] = max(col_widths.get(c, min_w), w) for c, w in col_widths.items(): ws.column_dimensions[c].width = min(max(w, min_w), max_w) # ── Data ────────────────────────────────────────────────────────────────────── def nacti_odbornosti(conn): with conn.cursor() as cur: cur.execute(""" SELECT vp.icp, o.nazev FROM vzp_pracoviste vp JOIN odbornost o ON o.kod = vp.odbornost WHERE CURDATE() BETWEEN vp.platnost_od AND vp.platnost_do ORDER BY vp.platnost_od DESC """) result = {} for row in cur.fetchall(): result.setdefault(row["icp"], row["nazev"]) return result def odbornost_z_icp(icp, slovnik): if not icp or len(icp) < 3: return "" return slovnik.get(icp, f"odb. {icp[-3:]}") def nacti_predpisy(conn, limit): with conn.cursor() as cur: cur.execute(""" SELECT p.datum_vystaveni, z.pacient_prijmeni, z.pacient_jmena, z.pacient_datum_narozeni, COALESCE(v.nazev, p.nazev) AS vydany_lek, v.nazev IS NULL AS nevyzvednuto, p.atc, p.navod, pr.prijmeni AS lekar_prijmeni, pr.jmena AS lekar_jmena, pr.icp, pr.pzs_nazev, pr.ulice, pr.psc, pr.mesto, rd.stav, rd.druh_pojisteni FROM predpis p JOIN zprava z ON z.id = p.zprava_id JOIN predepisujici pr ON pr.lekar_kod = p.kod_predepisujiciho LEFT JOIN vydej v ON v.id_lp_predpis = p.id_lp_predpis LEFT JOIN recept_plp rp ON rp.id_lp = p.id_lp_predpis LEFT JOIN recept_doklad rd ON rd.id_dokladu = rp.id_dokladu ORDER BY p.datum_vystaveni DESC, p.id DESC LIMIT %s """, (limit,)) return cur.fetchall() # ── Verzování souboru ───────────────────────────────────────────────────────── def versioned_path(dir_: Path, dnes: str) -> Path: zaklad = dir_ / f"report_predpisy_{dnes}.xlsx" if not zaklad.exists(): return zaklad v = 2 while True: p = dir_ / f"report_predpisy_{dnes}_v{v}.xlsx" if not p.exists(): return p v += 1 # ── Sestavení sešitu ────────────────────────────────────────────────────────── def vytvor_excel(rows, odbornosti, dnes): wb = Workbook() ws = wb.active ws.title = "Predpisy" N = 8 # počet sloupců # ── Záhlaví ─────────────────────────────────────────────────────────────── ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=N) title = ws.cell(row=1, column=1, value=f"PŘEHLED RECEPTŮ — posledních {LIMIT}") title.font = Font(name="Arial", bold=True, size=14, color=C_HEADER_FG) title.fill = fill(C_HEADER_BG) title.alignment = Alignment(horizontal="left", vertical="center", indent=1) ws.row_dimensions[1].height = 32 info_radky = [ ("Datum tisku:", datetime.today().strftime("%d.%m.%Y")), ("Počet záznamů:", str(len(rows))), ("Nejstarší datum:", str(rows[-1]["datum_vystaveni"]) if rows else ""), ("Nejnovější datum:", str(rows[0]["datum_vystaveni"]) if rows else ""), ] for i, (label, val) in enumerate(info_radky, 2): ws.merge_cells(start_row=i, start_column=1, end_row=i, end_column=2) ws.merge_cells(start_row=i, start_column=3, end_row=i, end_column=N) lbl = ws.cell(row=i, column=1, value=label) lbl.font = Font(name="Arial", bold=True, size=10) lbl.fill = fill(C_INFO_BG) lbl.alignment = Alignment(vertical="center", indent=1) v = ws.cell(row=i, column=3, value=val) v.font = Font(name="Arial", size=10) v.fill = fill(C_INFO_BG) v.alignment = Alignment(vertical="center") ws.row_dimensions[i].height = 16 row = len(info_radky) + 3 # prázdný řádek # ── Tabulka ─────────────────────────────────────────────────────────────── row = zapis_nadpis_sekce(ws, row, f"RECEPTY (celkem {len(rows)})", N) row = zapis_hlavicku(ws, row, [ "#", "Datum", "Pacient", "Vydaný lék / ATC", "Návod", "Lékař", "Odbornost", "Pracoviště a adresa", ]) for i, r in enumerate(rows, 1): nevyzv = bool(r["nevyzvednuto"]) pacient = f"{r['pacient_prijmeni']} {r['pacient_jmena']}".strip() lekar = f"{r['lekar_prijmeni']} {r['lekar_jmena']}".strip() odb = odbornost_z_icp(r["icp"], odbornosti) adresa = ", ".join(filter(None, [ r.get("pzs_nazev") or "", r.get("ulice") or "", f"{r.get('psc') or ''} {r.get('mesto') or ''}".strip(), ])) lek_atc = r["vydany_lek"] or "" if r.get("atc"): lek_atc += f"\n{r['atc']}" stav_text = "" if nevyzv: stav_text = " *NV" elif r.get("stav") == "ZRUSENY": stav_text = " *ZR" datum_str = (r["datum_vystaveni"].strftime("%d.%m.%Y") if r["datum_vystaveni"] else "") row = zapis_radek(ws, row, [ i, datum_str, pacient, lek_atc + stav_text, r.get("navod") or "", lekar, odb, adresa, ], highlight=nevyzv) # ── Dokončení ───────────────────────────────────────────────────────────── autofit(ws) ws.freeze_panes = "A7" # zmraz záhlaví + info řádky return wb def main(): conn = pymysql.connect(**DB) print("Nacitam odbornosti...") odbornosti = nacti_odbornosti(conn) print(f"Nacitam poslednich {LIMIT} receptu...") rows = nacti_predpisy(conn, LIMIT) conn.close() print(f" Nacteno: {len(rows)} zaznamu") dnes = date.today().isoformat() wb = vytvor_excel(rows, odbornosti, dnes) soubor = versioned_path(VYSTUP_DIR, dnes) wb.save(soubor) print(f"Ulozeno: {soubor}") if __name__ == "__main__": main()