Files
recept/report/report_predpisy.py
2026-04-16 14:20:38 +02:00

202 lines
7.7 KiB
Python

"""
Report posledních receptů — generuje HTML soubor.
Spuštění:
python report/report_predpisy.py
Výstup:
report/report_predpisy.html
"""
from pathlib import Path
from datetime import date
import pymysql
import pymysql.cursors
# ── Konfigurace ───────────────────────────────────────────────────────────────
DB = dict(
host = "192.168.1.76",
user = "root",
password = "Vlado9674+",
database = "medicus",
charset = "utf8mb4",
cursorclass = pymysql.cursors.DictCursor,
)
LIMIT = 100
VYSTUP = Path(__file__).parent / "report_predpisy.html"
# ── Odbornosti ────────────────────────────────────────────────────────────────
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:]}")
# ── Data ──────────────────────────────────────────────────────────────────────
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()
# ── HTML ──────────────────────────────────────────────────────────────────────
def stav_badge(stav, nevyzvednuto):
if nevyzvednuto:
return '<span class="badge badge-nv">nevyzvednut</span>'
if stav == "PLNE_VYDANY":
return '<span class="badge badge-ok">vydán</span>'
if stav == "CASTECNE_VYDANY":
return '<span class="badge badge-partial">část. vydán</span>'
if stav == "ZRUSENY":
return '<span class="badge badge-cancel">zrušen</span>'
if stav == "PRIPRAVOVANY":
return '<span class="badge badge-prep">připravován</span>'
if stav == "PREDEPSANY":
return '<span class="badge badge-pred">předepsán</span>'
return ""
def e(s):
"""HTML escape."""
if s is None:
return ""
return str(s).replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
def render_html(rows, odbornosti, dnes):
radky = []
for i, r in enumerate(rows, 1):
lekar = f"{e(r['lekar_prijmeni'])} {e(r['lekar_jmena'])}".strip()
pacient = f"{e(r['pacient_prijmeni'])} {e(r['pacient_jmena'])}".strip()
odb = e(odbornost_z_icp(r["icp"], odbornosti))
adresa = ", ".join(filter(None, [e(r["pzs_nazev"]), e(r["ulice"]),
f"{e(r['psc'])} {e(r['mesto'])}".strip()]))
badge = stav_badge(r["stav"], r["nevyzvednuto"])
tr_class = "tr-nv" if r["nevyzvednuto"] else ("tr-even" if i % 2 == 0 else "")
radky.append(f"""
<tr class="{tr_class}">
<td class="num">{i}</td>
<td class="datum">{e(r['datum_vystaveni'])}</td>
<td>{pacient}<br><small>{e(r['pacient_datum_narozeni'])}</small></td>
<td><strong>{e(r['vydany_lek'])}</strong>{badge}<br><small class="atc">{e(r['atc'])}</small></td>
<td class="navod">{e(r['navod'])}</td>
<td>{lekar}<br><small>{odb}</small></td>
<td class="adresa">{adresa}</td>
</tr>""")
return f"""<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>Přehled receptů</title>
<style>
* {{ box-sizing: border-box; margin: 0; padding: 0; }}
body {{ font-family: Arial, sans-serif; font-size: 13px; background: #f4f6f9; color: #222; }}
header {{ background: #1F4E79; color: #fff; padding: 18px 28px; }}
header h1 {{ font-size: 20px; font-weight: bold; }}
header p {{ font-size: 12px; opacity: .8; margin-top: 4px; }}
.wrap {{ padding: 20px 28px; }}
table {{ width: 100%; border-collapse: collapse; background: #fff; border-radius: 6px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,.1); }}
thead tr {{ background: #1F4E79; color: #fff; font-size: 12px; }}
thead th {{ padding: 10px 10px; text-align: left; font-weight: 600; }}
tbody td {{ padding: 8px 10px; border-bottom: 1px solid #dce6f1; vertical-align: top; }}
tbody tr:last-child td {{ border-bottom: none; }}
.tr-even {{ background: #EBF3FB; }}
.tr-nv {{ background: #FCE4D6; }}
.num {{ color: #888; width: 36px; text-align: right; }}
.datum {{ white-space: nowrap; width: 90px; }}
.atc {{ color: #666; }}
.navod {{ max-width: 200px; color: #444; }}
.adresa {{ font-size: 11px; color: #555; max-width: 180px; }}
small {{ font-size: 11px; color: #666; }}
.badge {{ display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 10px; font-size: 10px; font-weight: bold; vertical-align: middle; }}
.badge-ok {{ background: #d4edda; color: #155724; }}
.badge-nv {{ background: #FCE4D6; color: #c0392b; }}
.badge-partial {{ background: #fff3cd; color: #856404; }}
.badge-cancel {{ background: #e2e3e5; color: #383d41; }}
.badge-pred {{ background: #d1ecf1; color: #0c5460; }}
.badge-prep {{ background: #e8daef; color: #6c3483; }}
</style>
</head>
<body>
<header>
<h1>Přehled receptů — posledních {LIMIT}</h1>
<p>Vygenerováno: {dnes} &nbsp;|&nbsp; Počet záznamů: {len(rows)}</p>
</header>
<div class="wrap">
<table>
<thead>
<tr>
<th>#</th>
<th>Datum</th>
<th>Pacient</th>
<th>Vydaný lék</th>
<th>Návod</th>
<th>Lékař / Odbornost</th>
<th>Pracoviště</th>
</tr>
</thead>
<tbody>
{"".join(radky)}
</tbody>
</table>
</div>
</body>
</html>"""
def main():
conn = pymysql.connect(**DB)
print("Načítám odbornosti...")
odbornosti = nacti_odbornosti(conn)
print(f"Načítám posledních {LIMIT} receptů...")
rows = nacti_predpisy(conn, LIMIT)
conn.close()
html = render_html(rows, odbornosti, date.today().isoformat())
VYSTUP.write_text(html, encoding="utf-8")
print(f"Hotovo: {VYSTUP}")
if __name__ == "__main__":
main()