This commit is contained in:
2026-03-31 14:08:53 +02:00
parent 3141875629
commit 4950c00309
5 changed files with 1357 additions and 0 deletions
@@ -0,0 +1,410 @@
import os
import time
import fdb
import openpyxl
import xlwings as xw
from datetime import datetime, date
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font, PatternFill, Alignment
# --- Konfigurace ---
PathToSaveCSV = r"u:\Dropbox\!!!Days\Downloads Z230"
timestr = time.strftime("%Y-%m-%d_%H-%M-%S_")
output_path = os.path.join(PathToSaveCSV, timestr + "Pacienti.xlsx")
# --- Smazání předchozích verzí ---
for fname in os.listdir(PathToSaveCSV):
if fname.endswith("Pacienti.xlsx"):
try:
os.remove(os.path.join(PathToSaveCSV, fname))
except Exception as e:
print(f"Nelze smazat {fname}: {e}")
# --- Připojení k DB ---
con = fdb.connect(
host='localhost', database=r'c:\MEDICUS 3\data\medicus.FDB',
user='sysdba', password='masterkey', charset='WIN1250'
)
cur = con.cursor()
wb = openpyxl.Workbook()
# =====================
# Pomocné funkce
# =====================
# Styly pro posudky
HEADER_FILL = PatternFill('solid', fgColor='2F5496')
HEADER_FONT = Font(bold=True, color='FFFFFF')
ZEBRA_FILL = PatternFill('solid', fgColor='DCE6F1')
GREEN_FILL = PatternFill('solid', fgColor='C6EFCE')
GREEN_FONT = Font(bold=True, color='276221')
def style_header(ws):
for cell in ws[1]:
cell.fill = HEADER_FILL
cell.font = HEADER_FONT
cell.alignment = Alignment(horizontal='center')
def autofit_ws(ws):
for col in ws.columns:
max_len = max((len(str(cell.value)) if cell.value is not None else 0) for cell in col)
ws.column_dimensions[get_column_letter(col[0].column)].width = min(max_len + 2, 50)
def sanitize(val):
"""Nahradí znaky neplatné pro Excel: µ → u, ostatní → _"""
if not isinstance(val, str):
return val
result = []
for ch in val:
if ch == 'µ':
result.append('u')
elif ord(ch) < 32 and ch not in '\t\n\r':
result.append('_')
elif ord(ch) in (0xFFFE, 0xFFFF) or 0xD800 <= ord(ch) <= 0xDFFF:
result.append('_')
else:
result.append(ch)
return ''.join(result)
def fmt(val):
return '' if val is None else sanitize(val)
def parse_data(data_str):
"""Parsuje key=value text z HISTDOC.DATA do slovníku."""
result = {}
if not data_str:
return result
for line in data_str.splitlines():
if '=' in line:
key, _, val = line.partition('=')
result[key.strip()] = val.strip()
return result
def parse_date(val):
"""Převede 'D:DD.MM.YYYY' na datetime.date."""
if val and val.startswith('D:'):
try:
return datetime.strptime(val[2:], '%d.%m.%Y').date()
except ValueError:
return val
return val
VYKONY_CONDITION = """
(datose >= vykony.platiod AND datose <= vykony.platido)
OR (datose >= vykony.platiod AND vykony.platido IS NULL)
"""
VYKONY_HEADERS = ["Rodne cislo", "Jmeno", "Datum vykonu", "Kod", "Název", "Dg.", "Body"]
def add_vykony_sheet(sheet_name, kody):
"""Přidá list s výkony filtrovanými podle seznamu kódů."""
kod_list = ", ".join(str(k) for k in kody)
cur.execute(f"""
SELECT dokladd.rodcis,
TRIM(prijmeni) || ', ' || TRIM(jmeno),
dokladd.datose, dokladd.kod, vykony.naz, dokladd.ddgn, dokladd.body
FROM dokladd
LEFT JOIN kar ON dokladd.rodcis = kar.rodcis
JOIN vykony ON dokladd.kod = vykony.kod
WHERE ({VYKONY_CONDITION})
AND dokladd.kod IN ({kod_list})
ORDER BY datose DESC, dokladd.rodcis, dokladd.kod
""")
rows = cur.fetchall()
print(f"{sheet_name}: {len(rows)}")
ws = wb.create_sheet(sheet_name)
ws.append(VYKONY_HEADERS)
for row in rows:
ws.append(list(row))
# =====================
# List: Registrovaní
# =====================
cur.execute("""
SELECT rodcis, prijmeni, jmeno, datum_registrace, registr.idpac, poj
FROM registr
JOIN kar ON registr.idpac = kar.idpac
WHERE kar.vyrazen != 'A'
AND kar.rodcis IS NOT NULL
AND idicp != 0
AND datum_zruseni IS NULL
""")
rows = cur.fetchall()
print(f"Registrovaní: {len(rows)}")
ws = wb.active
ws.title = 'Registrovani'
ws.append(["Rodne cislo", "Prijmeni", "Jmeno", "Datum registrace", "ID pacienta", "Pojistovna"])
for row in rows:
ws.append(list(row))
# =====================
# List: Očkování
# =====================
cur.execute("""
SELECT rodcis, prijmeni, jmeno, ockzaz.datum, kodmz, ockzaz.poznamka, latka, nazev, expire
FROM registr
JOIN kar ON registr.idpac = kar.idpac
JOIN ockzaz ON registr.idpac = ockzaz.idpac
WHERE datum_zruseni IS NULL
AND kar.vyrazen != 'A'
AND kar.rodcis IS NOT NULL
AND idicp != 0
ORDER BY ockzaz.datum DESC
""")
rows = cur.fetchall()
print(f"Očkování: {len(rows)}")
ws = wb.create_sheet("Očkování")
ws.append(["Rodne cislo", "Prijmeni", "Jmeno", "Datum ockovani", "Kod MZ", "Sarze", "Latka", "Nazev", "Expirace"])
for row in rows:
ws.append(list(row))
# =====================
# List: Recepty
# =====================
cur.execute("""
SELECT kar.rodcis,
TRIM(kar.prijmeni) || ' ' || SUBSTRING(kar.jmeno FROM 1 FOR 1) || '.' AS jmeno,
recept.datum,
TRIM(recept.lek) || ' ' || TRIM(recept.dop) AS lek,
recept.expori AS Poc,
CASE WHEN recept.opakovani IS NULL THEN 1 ELSE recept.opakovani END AS OP,
recept.uhrada,
recept.dsig,
recept.NOTIFIKACE_KONTAKT AS notifikace,
recept_epodani.erp,
recept_epodani.vystavitel_jmeno,
recept.atc,
recept.CENAPOJ,
recept.cenapac
FROM recept
LEFT JOIN RECEPT_EPODANI ON recept.id_epodani = recept_epodani.id
LEFT JOIN kar ON recept.idpac = kar.idpac
ORDER BY datum DESC, erp DESC
""")
rows = cur.fetchall()
print(f"Recepty: {len(rows)}")
ws = wb.create_sheet("Recepty")
ws.append(["Rodné číslo", "Jméno", "Datum vystavení", "Název leku", "Poč.", "Op.", "Úhr.",
"Da signa", "Notifikace", "eRECEPT", "Vystavil", "ATC", "Cena pojišťovna", "Cena pacient"])
for row in rows:
ws.append([sanitize(v) if isinstance(v, str) else v for v in row])
# =====================
# List: Výkony všechny
# =====================
cur.execute(f"""
SELECT dokladd.rodcis,
TRIM(prijmeni) || ', ' || TRIM(jmeno),
dokladd.datose, dokladd.kod, dokladd.pocvyk, dokladd.ddgn, dokladd.body, vykony.naz
FROM kar
JOIN dokladd ON kar.rodcis = dokladd.rodcis
JOIN vykony ON dokladd.kod = vykony.kod
WHERE {VYKONY_CONDITION}
ORDER BY dokladd.datose DESC, dokladd.rodcis
""")
rows = cur.fetchall()
print(f"Výkony: {len(rows)}")
ws = wb.create_sheet("Vykony")
ws.append(["Rodne cislo", "Jmeno", "Datum vykonu", "Kod", "Pocet", "Dg.", "Body", "Nazev"])
for row in rows:
ws.append(list(row))
# =====================
# Listy: Neschopenky
# =====================
def pocet_dni(zacnes, konnes, pracne):
dnes = date.today()
if pracne == 'A':
return (dnes - zacnes).days if zacnes else "NA"
if pracne == 'N' and zacnes and konnes and zacnes <= konnes:
return (konnes - zacnes).days
return "NA"
def nes_row(r):
return (r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7],
pocet_dni(r[5], r[7], r[6]), r[8], r[9], r[10])
NES_HEADERS = ["ID pac", "Rodne cislo", "Jmeno", "Datum neschopenky", "Číslo neschopenky",
"Zacatek", "Aktivní?", "Konec", "Pocet dni", "Diagnoza zacatel", "Diagnoza konec", "Aktualizovano"]
cur.execute("""
SELECT nes.idpac, kar.rodcis,
TRIM(prijmeni) || ', ' || TRIM(jmeno),
nes.datnes, nes.ecn, nes.zacnes, nes.pracne, nes.konnes,
nes.diagno, nes.kondia, nes.updated
FROM nes
LEFT JOIN kar ON nes.idpac = kar.idpac
WHERE nes.datnes <= CURRENT_DATE
ORDER BY datnes DESC
""")
vse = cur.fetchall()
aktivni = [r for r in vse if r[6] == 'A']
print(f"Neschopenky: {len(vse)} celkem, {len(aktivni)} aktivních")
ws = wb.create_sheet("Neschopenky všechny")
ws.append(NES_HEADERS)
for r in vse:
ws.append(list(nes_row(r)))
ws = wb.create_sheet("Neschopenky aktivní")
ws.append(NES_HEADERS)
for r in aktivni:
ws.append(list(nes_row(r)))
# =====================
# Výkonové listy jednotlivé typy výkonů
# =====================
add_vykony_sheet('Preventivni prohlidky', [1022, 1021])
add_vykony_sheet('INR', [1443])
add_vykony_sheet('CRP', [2230, 9111])
add_vykony_sheet('Holter', [17129])
add_vykony_sheet('Prostata', [1130, 1131, 1132, 1133, 1134])
add_vykony_sheet('TOKS', [15118, 15119, 15120, 15121])
add_vykony_sheet('COVID', [1306])
add_vykony_sheet('Streptest', [2220])
# =====================
# List: Posudky řidičák MOTORVO (ruční)
# =====================
cur.execute("SELECT IDPACI, DATUM FROM HISTDOC WHERE TYP = 'EPOSMRO'")
eposmro_keys = set((r[0], r[1]) for r in cur.fetchall())
cur.execute("""
SELECT h.ID, h.DATUM, h.IDPACI,
k.PRIJMENI, k.JMENO, k.RODCIS,
h.DATA, h.PORCISLO, h.STAV, h.PRINTED, h.IDUZIV, h.CREATED
FROM HISTDOC h
JOIN KAR k ON k.IDPAC = h.IDPACI
WHERE h.TYP = 'MOTORVO'
ORDER BY h.ID DESC
""")
motorvo_rows = cur.fetchall()
print(f"MOTORVO: {len(motorvo_rows)}")
motorvo_headers = [
'ID', 'DATUM', 'IDPACI', 'PRIJMENI', 'JMENO', 'RODCIS',
'PorCislo', 'DatumVyd', 'DatKonec', 'DruhProh',
'Posouzeni', 'ZpusobPodminka', 'SkupinaPodminka', 'Skupiny',
'ePosudek', 'STAV', 'PRINTED', 'IDUZIV', 'CREATED'
]
ws = wb.create_sheet("Posudky řidičák")
ws.append(motorvo_headers)
epos_col_idx = motorvo_headers.index('ePosudek') + 1
for i, row in enumerate(motorvo_rows, start=2):
(hid, datum, idpac, prijmeni, jmeno, rodcis,
data_blob, porcislo, stav, printed, iduziv, created) = row
data = parse_data(data_blob)
if data.get('Posouzeni2') == 'T':
posouzeni = 'nezpůsobilý'
elif data.get('ZpusobPodminka') == 'B:1':
posouzeni = 'způsobilý s podmínkou'
elif data.get('Posouzeni') == 'T':
posouzeni = 'způsobilý'
else:
posouzeni = ''
ws.append([
hid, fmt(datum), idpac, fmt(prijmeni), fmt(jmeno), fmt(rodcis),
fmt(porcislo or data.get('PorCislo', '')),
parse_date(data.get('DatumVyd', '')),
parse_date(data.get('DatKonec', '')),
fmt(data.get('DruhProh', '')),
posouzeni,
fmt(data.get('ZpusobPodminka', '')),
fmt(data.get('SkupinaPodminka', '')),
fmt(data.get('ZpusobJe', '')),
'ANO' if (idpac, datum) in eposmro_keys else 'NE',
fmt(stav), fmt(printed), fmt(iduziv), fmt(created),
])
if i % 2 == 0:
for cell in ws[i]:
cell.fill = ZEBRA_FILL
cell = ws.cell(row=i, column=epos_col_idx)
if cell.value == 'ANO':
cell.fill = GREEN_FILL
cell.font = GREEN_FONT
style_header(ws)
ws.freeze_panes = 'A2'
autofit_ws(ws)
# =====================
# List: Posudky řidičák EPOSMRO (elektronická podání)
# =====================
cur.execute("""
SELECT h.ID, h.DATUM, h.IDPACI,
k.PRIJMENI, k.JMENO, k.RODCIS,
h.DATA, h.STAV, h.CREATED,
e.ID_PODANI, e.ODESLANO, e.STATUS
FROM HISTDOC h
JOIN KAR k ON k.IDPAC = h.IDPACI
LEFT JOIN HISTDOC_EPOSUDEK e ON e.ID_HISTDOC = h.ID
WHERE h.TYP = 'EPOSMRO'
ORDER BY h.ID DESC
""")
epos_rows = cur.fetchall()
print(f"EPOSMRO: {len(epos_rows)}")
ws = wb.create_sheet("ePosudky registr")
ws.append([
'ID', 'DATUM', 'IDPACI', 'PRIJMENI', 'JMENO', 'RODCIS',
'DatumVyd', 'DatKonec', 'DruhProhlidky', 'DruhPosudku',
'Vysledek', 'StavPosudku', 'TypAkce',
'STAV', 'CREATED', 'ID_PODANI', 'ODESLANO', 'STATUS_ODESL'
])
for i, row in enumerate(epos_rows, start=2):
(hid, datum, idpac, prijmeni, jmeno, rodcis,
data_blob, stav, created, id_podani, odeslano, status_odesl) = row
data = parse_data(data_blob)
ws.append([
hid, fmt(datum), idpac, fmt(prijmeni), fmt(jmeno), fmt(rodcis),
parse_date(data.get('DatumVystaveni', '')),
parse_date(data.get('PlatnostDo', '')),
fmt(data.get('DruhProhlidkyNazev', '')),
fmt(data.get('DruhPosudkuNazev', '')),
fmt(data.get('VysledekNazev', '')),
fmt(data.get('StavPosudkuNazev', '')),
fmt(data.get('TypAkceNazev', '')),
fmt(stav), fmt(created), fmt(id_podani), fmt(odeslano), fmt(status_odesl),
])
if i % 2 == 0:
for cell in ws[i]:
cell.fill = ZEBRA_FILL
style_header(ws)
ws.freeze_panes = 'A2'
autofit_ws(ws)
# =====================
# Autofilter na všech listech
# =====================
for ws in wb.worksheets:
ws.auto_filter.ref = f"A1:{get_column_letter(ws.max_column)}{ws.max_row}"
# =====================
# Uložení
# =====================
con.close()
wb.save(output_path)
print(f"Uloženo: {output_path}")
# =====================
# xlwings: autofit + centrování Recepty
# =====================
with xw.App(visible=False) as app:
wb_xw = xw.Book(output_path)
for sheet in wb_xw.sheets:
sheet.autofit()
for sloupec in ["C:C", "E:E", "F:F", "G:G", "I:I", "M:M", "N:N"]:
wb_xw.sheets['Recepty'].range(sloupec).api.HorizontalAlignment = 3
wb_xw.save()
wb_xw.close()
print("Hotovo.")