This commit is contained in:
2026-04-16 14:20:38 +02:00
parent e23735d07e
commit ef7c5d77dc
441 changed files with 1913 additions and 14 deletions
+268
View File
@@ -0,0 +1,268 @@
"""
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()