269 lines
10 KiB
Python
269 lines
10 KiB
Python
"""
|
|
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()
|