From 95927c304df9f8c7e85756d98ad5303106803251 Mon Sep 17 00:00:00 2001 From: Vladimir Buzalka Date: Sat, 11 Apr 2026 08:54:47 +0200 Subject: [PATCH] notebook vb --- .../HelpFiles/dekurz_report_test.py | 352 ++++++++++++++++++ MedicusWithClaudeDekurz/dekurz_report.py | 180 ++++++--- 2 files changed, 473 insertions(+), 59 deletions(-) create mode 100644 MedicusWithClaudeDekurz/HelpFiles/dekurz_report_test.py diff --git a/MedicusWithClaudeDekurz/HelpFiles/dekurz_report_test.py b/MedicusWithClaudeDekurz/HelpFiles/dekurz_report_test.py new file mode 100644 index 0000000..ee6eaec --- /dev/null +++ b/MedicusWithClaudeDekurz/HelpFiles/dekurz_report_test.py @@ -0,0 +1,352 @@ +import sys, io, re, os, glob +from datetime import date, datetime, timedelta +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') +import fdb +import openpyxl +from openpyxl.styles import Font, PatternFill, Alignment, Border, Side + +VYSTUPNI_ADRESAR = r'u:\Dropbox\Ordinace\Reporty' +NAZEV_REPORTU = 'Dekurzy_TEST' +DATUM_OD = (date.today() - timedelta(days=100)).strftime('%Y-%m-%d') +DATUM_DO = date.today().strftime('%Y-%m-%d') + +conn = fdb.connect( + dsn=r'localhost:c:\medicus 3\data\medicus.fdb', + user='SYSDBA', password='masterkey', charset='win1250' +) +cur = conn.cursor() + +cur.execute(f""" + SELECT d.DATUM, d.CAS, u.ZKRATKA, k.PRIJMENI, k.JMENO, k.RODCIS, k.POJ, d.DEKURS + FROM DEKURS d + JOIN KAR k ON k.IDPAC = d.IDPAC + LEFT JOIN UZIVATEL u ON u.IDUZI = d.IDUZI + WHERE d.DATUM >= '{DATUM_OD}' AND d.DATUM <= '{DATUM_DO}' + ORDER BY d.DATUM DESC, d.CAS DESC, k.PRIJMENI, k.JMENO +""") +raw_rows = cur.fetchall() + +TOP_TYPY = ['VykA', 'Rec', 'Files', 'MEDLAB', 'Lab', 'Ock', 'Nes', 'Lec', 'SpecVys', 'PlaPac'] + +def rtf_na_text(rtf): + """Jednoduchý převod RTF na čistý text.""" + # Odstraň info blok (bookmarky apod.) + text = re.sub(r'\{\\info.*?\}', '', rtf, flags=re.DOTALL) + # Odstraň ostatní skupiny v {} rekurzivně (fonty, barvy apod.) + for _ in range(6): + text = re.sub(r'\{[^{}]*\}', '', text) + # Nový řádek za \par \line + text = re.sub(r'\\par\b\s*', '\n', text) + text = re.sub(r'\\line\b\s*', '\n', text) + # Dekóduj RTF hex escape sekvence (\'xx) jako cp1250 → správná čeština + def decode_hex(m): + try: + return bytes.fromhex(m.group(1)).decode('cp1250') + except Exception: + return '' + text = re.sub(r"\\'([0-9a-fA-F]{2})", decode_hex, text) + # Odstraň ostatní RTF příkazy + text = re.sub(r'\\[a-zA-Z]+\-?[0-9]*\s?', '', text) + text = re.sub(r'[{}\\]', '', text) + # Vyčisti prázdné řádky a whitespace + lines = [l.strip() for l in text.splitlines()] + lines = [l for l in lines if l] + return '\n'.join(lines) + +# Parse dekurzů +rows = [] +for datum, cas, zkratka, prijmeni, jmeno, rodcis, poj, dekurs_blob in raw_rows: + rtf = dekurs_blob.read() if hasattr(dekurs_blob, 'read') else (dekurs_blob or '') + pocty = {} + ids_by_typ = {t: [] for t in TOP_TYPY} + ids_ostatni = [] + for nazev, typ, rid in re.findall(r'"([^"]+)","([A-Za-z]+):(\d+)"', rtf): + pocty[typ] = pocty.get(typ, 0) + 1 + if typ in ids_by_typ: + ids_by_typ[typ].append(int(rid)) + else: + ids_ostatni.append((typ, int(rid), nazev)) + top = [pocty.get(t, 0) for t in TOP_TYPY] + ostatni = sum(v for k, v in pocty.items() if k not in TOP_TYPY) + iniciala = jmeno[0] + '.' if jmeno and jmeno.strip() else '' + jmeno_cel = f"{prijmeni.strip()}, {iniciala}" if prijmeni else iniciala + text_dekurzu = rtf_na_text(rtf) + rows.append((datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_typ, ids_ostatni, text_dekurzu)) + +# ── Načtení detailů z DB ──────────────────────────────────────────────────── +def fetch_details(cur, table, pk, id_col, fields, ids): + if not ids: + return {} + result = {} + batch_size = 1000 + for i in range(0, len(ids), batch_size): + batch = ids[i:i+batch_size] + ph = ','.join('?' * len(batch)) + cur.execute(f"SELECT {pk}, {','.join(fields)} FROM {table} WHERE {id_col} IN ({ph})", batch) + for row in cur.fetchall(): + result[row[0]] = row[1:] + return result + +def get_ids(rows, typ): + return list({rid for *_, ids_by_typ, _, _text in rows for rid in ids_by_typ[typ]}) + +rec_det = fetch_details(cur, 'RECEPT', 'ID', 'ID', ['LEK','DSIG'], get_ids(rows,'Rec')) +vyka_det = fetch_details(cur, 'DOKLADD', 'ID', 'ID', ['KOD','DDGN','BODY'], get_ids(rows,'VykA')) +files_det = fetch_details(cur, 'FILES', 'ID', 'ID', ['FILENAME','DATUM'], get_ids(rows,'Files')) +medlab_det = fetch_details(cur, 'HISTDOC', 'ID', 'ID', ['DATUM','TYP'], get_ids(rows,'MEDLAB')) +lab_det = fetch_details(cur, 'LABVH', 'IDVH', 'IDVH', ['DATUM','CISLO'], get_ids(rows,'Lab')) +ock_det = fetch_details(cur, 'OCKZAZ', 'ID', 'ID', ['DATUM','LATKA'], get_ids(rows,'Ock')) +nes_det = fetch_details(cur, 'NES', 'ID', 'ID', ['ZACNES','KONNES'], get_ids(rows,'Nes')) +lec_det = fetch_details(cur, 'LECD', 'ID', 'ID', ['KOD','DATOSE'], get_ids(rows,'Lec')) +spec_det = fetch_details(cur, 'SPECVYS', 'IDSPECVYS','IDSPECVYS',['TYP','DATUM'], get_ids(rows,'SpecVys')) +pla_det = fetch_details(cur, 'PLA', 'IDPLA', 'IDPLA', ['DATUM','CENA','DOKLAD'], get_ids(rows,'PlaPac')) + +conn.close() +print(f"Načteno {len(rows)} dekurzů (období: {DATUM_OD} – {DATUM_DO})") + +# ── Styly ────────────────────────────────────────────────────────────────── +tenka_cara = Side(style='thin', color='AAAAAA') +ohraniceni = Border(left=tenka_cara, right=tenka_cara, top=tenka_cara, bottom=tenka_cara) +hl_font = Font(bold=True, color="FFFFFF") +hl_fill = PatternFill("solid", fgColor="2E75B6") +r_fill = [PatternFill("solid", fgColor="FFFFFF"), PatternFill("solid", fgColor="DCE6F1")] + +BARVY_LISTU = { + 'Recepty': ('1F6B33', 'E2EFDA'), + 'Výkony': ('2E4057', 'D6E4F0'), + 'Soubory': ('7B3F00', 'FAE5D3'), + 'Žádanky': ('4A235A', 'F5EEF8'), + 'Lab výsl.': ('145A32', 'D5F5E3'), + 'Očkování': ('7E5109', 'FDEBD0'), + 'Neschop.': ('922B21', 'FADBD8'), + 'Léčiva': ('1A5276', 'D6EAF8'), + 'SpecVys': ('0B5345', 'D1F2EB'), + 'Platby': ('4D5656', 'EAECEE'), + 'Ostatní': ('2C3E50', 'EBF5FB'), +} + +def zapis_hlavicku(ws, sloupce, sirky, barva_hex): + hl_fill_l = PatternFill("solid", fgColor=barva_hex) + for col, (nazev, sirka) in enumerate(zip(sloupce, sirky), start=1): + cell = ws.cell(row=1, column=col, value=nazev) + cell.font = hl_font + cell.fill = hl_fill_l + cell.alignment = Alignment(horizontal='center') + cell.border = ohraniceni + ws.column_dimensions[cell.column_letter].width = sirka + +def zapis_radek(ws, row_i, hodnoty, zarovnani, barva_hex): + fill = PatternFill("solid", fgColor="FFFFFF") if row_i % 2 == 0 \ + else PatternFill("solid", fgColor=barva_hex) + for col_i, (val, align) in enumerate(zip(hodnoty, zarovnani), start=1): + cell = ws.cell(row=row_i, column=col_i, value=val) + cell.fill = fill + cell.border = ohraniceni + cell.alignment = Alignment(horizontal=align) + if col_i == 1 and isinstance(val, __import__('datetime').date): + cell.number_format = 'DD.MM.YYYY' + +def hyperlink_cell(ws, row_i, col_i, cil_list, cil_radek, text, barva_hex): + fill = PatternFill("solid", fgColor="FFFFFF") if row_i % 2 == 0 \ + else PatternFill("solid", fgColor=barva_hex) + cell = ws.cell(row=row_i, column=col_i) + cell.value = str(text) + # Název listu s mezerou musí být v apostrofech + sheet_ref = f"'{cil_list}'" if ' ' in cil_list else cil_list + cell.hyperlink = f'#{sheet_ref}!A{cil_radek}' + cell.font = Font(color="0000FF", underline='single') + cell.fill = fill + cell.border = ohraniceni + cell.alignment = Alignment(horizontal='center') + +# ── Workbook ─────────────────────────────────────────────────────────────── +wb = openpyxl.Workbook() + +LISTY = [ + ('Recepty', 'Rec', rec_det, ['Datum','Jméno','Recept','Dávkování'], [12,25,25,12], None), + ('Výkony', 'VykA', vyka_det, ['Datum','Jméno','Kód výkonu','Diagnóza','Body'], [12,25,14,10,8], None), + ('Soubory', 'Files', files_det, ['Datum','Jméno','Soubor','Datum souboru'], [12,25,35,14], None), + ('Žádanky', 'MEDLAB', medlab_det, ['Datum','Jméno','Typ'], [12,25,15], None), + ('Lab výsl.', 'Lab', lab_det, ['Datum','Jméno','Číslo'], [12,25,20], None), + ('Očkování', 'Ock', ock_det, ['Datum','Jméno','Datum očkování','Vakcína'], [12,25,14,30], None), + ('Neschop.', 'Nes', nes_det, ['Datum','Jméno','Od','Do'], [12,25,12,12], None), + ('Léčiva', 'Lec', lec_det, ['Datum','Jméno','Kód','Datum výkonu'], [12,25,12,14], None), + ('SpecVys', 'SpecVys', spec_det, ['Datum','Jméno','Typ vyšetření','Datum vyšetření'], [12,25,25,14], None), + ('Platby', 'PlaPac', pla_det, ['Datum','Jméno','Datum platby','Částka','Doklad'], [12,25,14,12,15], None), + ('Ostatní', None, None, ['Datum','Jméno','Typ','ID','Název'], [12,25,12,10,30], None), +] + +ws_d = wb.active +ws_d.title = "Dekurz" + +# List "Text dekurzu" hned za Dekurzem +ws_text = wb.create_sheet("Text dekurzu") + +ws_listy = {} +for nazev, *_ in LISTY: + ws_listy[nazev] = wb.create_sheet(nazev) + +for nazev, typ, det, sloupce, sirky, _ in LISTY: + barva_hl, _ = BARVY_LISTU[nazev] + zapis_hlavicku(ws_listy[nazev], sloupce, sirky, barva_hl) + ws_listy[nazev].freeze_panes = 'A2' + +# Záhlaví listu "Text dekurzu" +zapis_hlavicku(ws_text, + ['Datum', 'Čas', 'Lékař', 'Jméno', 'Rodné číslo', 'Text dekurzu'], + [12, 8, 8, 25, 14, 100], + '2E75B6') +ws_text.freeze_panes = 'A2' +row_ptr_text = 2 + +# Zobrazované názvy sloupců pro TOP_TYPY (stejné pořadí) +NAZVY_TYPY = ['VykA', 'Rec', 'Files', 'Žádanky', 'Lab výsl.', 'Ock', 'Nes', 'Lec', 'SpecVys', 'PlaPac'] + +# Záhlaví Dekurz – sloupce A–R (bez textu) +nazvy_d = ['Datum', 'Čas', 'Lékař', 'Jméno', 'Rodné číslo', 'Pojišťovna'] + ['HodVyk'] + NAZVY_TYPY + ['Ostatní'] +sirky_d = [12, 8, 8, 25, 14, 12 ] + [10] + [38, 8, 8, 8, 8, 8, 8, 8, 8, 8] + [8] +zapis_hlavicku(ws_d, nazvy_d, sirky_d, '2E75B6') +ws_d.freeze_panes = 'A2' +ws_d.auto_filter.ref = f"A1:R{len(rows)+1}" + +row_ptr = {nazev: 2 for nazev, *_ in LISTY} + +# ── Plnění dat ───────────────────────────────────────────────────────────── +def get_det_hodnoty(typ, rid, datum, jmeno_cel): + if typ == 'Rec': + d = rec_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[0] or '', d[1] or ''] + elif typ == 'VykA': + d = vyka_det.get(rid, ('', '', 0)) + return [datum, jmeno_cel, d[0] or '', (d[1] or '').strip(), d[2] or 0] + elif typ == 'Files': + d = files_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[0] or '', d[1]] + elif typ == 'MEDLAB': + d = medlab_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[1] or ''] + elif typ == 'Lab': + d = lab_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[1] or ''] + elif typ == 'Ock': + d = ock_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[0], d[1] or ''] + elif typ == 'Nes': + d = nes_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[0], d[1]] + elif typ == 'Lec': + d = lec_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[0] or '', d[1]] + elif typ == 'SpecVys': + d = spec_det.get(rid, ('', '')) + return [datum, jmeno_cel, d[0] or '', d[1]] + elif typ == 'PlaPac': + d = pla_det.get(rid, ('', '', '')) + return [datum, jmeno_cel, d[0], d[1], d[2] or ''] + return [] + +ZAROVNANI = { + 'Recepty': ['left','left','left','center'], + 'Výkony': ['left','left','center','center','right'], + 'Soubory': ['left','left','left','left'], + 'MedLab': ['left','left','center'], + 'Lab': ['left','left','center'], + 'Očkování': ['left','left','left','left'], + 'Neschop.': ['left','left','left','left'], + 'Léčiva': ['left','left','center','left'], + 'SpecVys': ['left','left','left','left'], + 'Platby': ['left','left','left','right','center'], + 'Ostatní': ['left','left','center','center','left'], +} + +for row_i, (datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_typ, ids_ostatni, text_dekurzu) in enumerate(rows, start=2): + fill_d = r_fill[row_i % 2] + for col_i in range(1, len(nazvy_d) + 1): + ws_d.cell(row=row_i, column=col_i).fill = fill_d + ws_d.cell(row=row_i, column=col_i).border = ohraniceni + + ws_d.cell(row=row_i, column=1, value=datum).number_format = 'DD.MM.YYYY' + ws_d.cell(row=row_i, column=2, value=str(cas)[:5] if cas else '').alignment = Alignment(horizontal='center') + ws_d.cell(row=row_i, column=3, value=zkratka or '').alignment = Alignment(horizontal='center') + ws_d.cell(row=row_i, column=4, value=jmeno_cel) + # Sloupec 5 – Rodné číslo jako hyperlink na list "Text dekurzu" + hyperlink_cell(ws_d, row_i, 5, 'Text dekurzu', row_ptr_text, rodcis or '', 'DCE6F1') + ws_d.cell(row=row_i, column=6, value=poj or '').alignment = Alignment(horizontal='center') + + # Sloupec G – HodVyk (součet bodů všech výkonů dekurzu) + hodvyk = sum((vyka_det.get(rid, ('', '', 0))[2] or 0) for rid in ids_by_typ['VykA']) + cell_hv = ws_d.cell(row=row_i, column=7, value=hodvyk if hodvyk else '') + cell_hv.alignment = Alignment(horizontal='center') + + for col_off, (typ, pocet) in enumerate(zip(TOP_TYPY, top)): + col_i = 8 + col_off + if pocet == 0: + continue + nazev_listu = next((n for n, t, *_ in LISTY if t == typ), None) + if nazev_listu and ids_by_typ[typ]: + _, barva_ll = BARVY_LISTU[nazev_listu] + # Pro výkony (VykA) přidej kódy do závorky + if typ == 'VykA': + kody = [str(vyka_det.get(rid, ('',))[0] or '').strip() for rid in ids_by_typ[typ]] + kody_str = ', '.join(k for k in kody if k) + display_text = f"{pocet} ({kody_str})" if kody_str else pocet + else: + display_text = pocet + hyperlink_cell(ws_d, row_i, col_i, nazev_listu, row_ptr[nazev_listu], display_text, barva_ll[1:] if len(barva_ll) > 6 else 'DCE6F1') + ws_det = ws_listy[nazev_listu] + barva_hl, barva_r = BARVY_LISTU[nazev_listu] + for rid in ids_by_typ[typ]: + hodnoty = get_det_hodnoty(typ, rid, datum, jmeno_cel) + zarovnani_l = ZAROVNANI.get(nazev_listu, ['left']*10) + zapis_radek(ws_det, row_ptr[nazev_listu], hodnoty, zarovnani_l, barva_r) + row_ptr[nazev_listu] += 1 + else: + ws_d.cell(row=row_i, column=col_i, value=pocet).alignment = Alignment(horizontal='center') + + if ostatni: + ws_det = ws_listy['Ostatní'] + barva_hl, barva_r = BARVY_LISTU['Ostatní'] + hyperlink_cell(ws_d, row_i, 18, 'Ostatní', row_ptr['Ostatní'], ostatni, barva_r) + for typ, rid, nazev in ids_ostatni: + zapis_radek(ws_det, row_ptr['Ostatní'], + [datum, jmeno_cel, typ, rid, nazev], + ZAROVNANI['Ostatní'], barva_r) + row_ptr['Ostatní'] += 1 + + # Zápis do listu "Text dekurzu" + fill_t = r_fill[row_ptr_text % 2] + for col_i in range(1, 7): + ws_text.cell(row=row_ptr_text, column=col_i).fill = fill_t + ws_text.cell(row=row_ptr_text, column=col_i).border = ohraniceni + c1 = ws_text.cell(row=row_ptr_text, column=1, value=datum) + c1.number_format = 'DD.MM.YYYY' + c1.alignment = Alignment(horizontal='left', vertical='center') + ws_text.cell(row=row_ptr_text, column=2, value=str(cas)[:5] if cas else '').alignment = Alignment(horizontal='center', vertical='center') + ws_text.cell(row=row_ptr_text, column=3, value=zkratka or '').alignment = Alignment(horizontal='center', vertical='center') + ws_text.cell(row=row_ptr_text, column=4, value=jmeno_cel).alignment = Alignment(horizontal='left', vertical='center') + ws_text.cell(row=row_ptr_text, column=5, value=rodcis or '').alignment = Alignment(horizontal='left', vertical='center') + cell_txt = ws_text.cell(row=row_ptr_text, column=6, value=text_dekurzu) + cell_txt.alignment = Alignment(horizontal='left', vertical='top', wrap_text=True) + row_ptr_text += 1 + +# Autofiltr na detailních listech +for nazev, *_ in LISTY: + ws = ws_listy[nazev] + max_col = ws.max_column + max_row = ws.max_row + if max_row > 1: + ws.auto_filter.ref = f"A1:{ws.cell(row=1, column=max_col).column_letter}{max_row}" + +# Smazat starý TEST report +for stary in glob.glob(os.path.join(VYSTUPNI_ADRESAR, f'* {NAZEV_REPORTU}.xlsx')): + os.remove(stary) + print(f"Smazán: {stary}") + +# Uložit nový +os.makedirs(VYSTUPNI_ADRESAR, exist_ok=True) +casova_znacka = datetime.now().strftime('%Y-%m-%d %H-%M-%S') +vystup = os.path.join(VYSTUPNI_ADRESAR, f'{casova_znacka} {NAZEV_REPORTU}.xlsx') +wb.save(vystup) +print(f"Uloženo: {vystup}") +for nazev, *_ in LISTY: + print(f" {nazev}: {row_ptr[nazev]-2} řádků") diff --git a/MedicusWithClaudeDekurz/dekurz_report.py b/MedicusWithClaudeDekurz/dekurz_report.py index d832a36..a526c7b 100644 --- a/MedicusWithClaudeDekurz/dekurz_report.py +++ b/MedicusWithClaudeDekurz/dekurz_report.py @@ -26,7 +26,32 @@ cur.execute(f""" """) raw_rows = cur.fetchall() -TOP_TYPY = ['Rec', 'VykA', 'Files', 'MEDLAB', 'Lab', 'Ock', 'Nes', 'Lec', 'SpecVys', 'PlaPac'] +TOP_TYPY = ['VykA', 'Rec', 'Files', 'MEDLAB', 'Lab', 'Ock', 'Nes', 'Lec', 'SpecVys', 'PlaPac'] + +def rtf_na_text(rtf): + """Jednoduchý převod RTF na čistý text.""" + # Odstraň info blok (bookmarky apod.) + text = re.sub(r'\{\\info.*?\}', '', rtf, flags=re.DOTALL) + # Odstraň ostatní skupiny v {} rekurzivně (fonty, barvy apod.) + for _ in range(6): + text = re.sub(r'\{[^{}]*\}', '', text) + # Nový řádek za \par \line + text = re.sub(r'\\par\b\s*', '\n', text) + text = re.sub(r'\\line\b\s*', '\n', text) + # Dekóduj RTF hex escape sekvence (\'xx) jako cp1250 → správná čeština + def decode_hex(m): + try: + return bytes.fromhex(m.group(1)).decode('cp1250') + except Exception: + return '' + text = re.sub(r"\\'([0-9a-fA-F]{2})", decode_hex, text) + # Odstraň ostatní RTF příkazy + text = re.sub(r'\\[a-zA-Z]+\-?[0-9]*\s?', '', text) + text = re.sub(r'[{}\\]', '', text) + # Vyčisti prázdné řádky a whitespace + lines = [l.strip() for l in text.splitlines()] + lines = [l for l in lines if l] + return '\n'.join(lines) # Parse dekurzů rows = [] @@ -45,7 +70,8 @@ for datum, cas, zkratka, prijmeni, jmeno, rodcis, poj, dekurs_blob in raw_rows: ostatni = sum(v for k, v in pocty.items() if k not in TOP_TYPY) iniciala = jmeno[0] + '.' if jmeno and jmeno.strip() else '' jmeno_cel = f"{prijmeni.strip()}, {iniciala}" if prijmeni else iniciala - rows.append((datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_typ, ids_ostatni)) + text_dekurzu = rtf_na_text(rtf) + rows.append((datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_typ, ids_ostatni, text_dekurzu)) # ── Načtení detailů z DB ──────────────────────────────────────────────────── def fetch_details(cur, table, pk, id_col, fields, ids): @@ -62,10 +88,10 @@ def fetch_details(cur, table, pk, id_col, fields, ids): return result def get_ids(rows, typ): - return list({rid for _, _, _, _, _, _, _, _, ids_by_typ, _ in rows for rid in ids_by_typ[typ]}) + return list({rid for *_, ids_by_typ, _, _text in rows for rid in ids_by_typ[typ]}) rec_det = fetch_details(cur, 'RECEPT', 'ID', 'ID', ['LEK','DSIG'], get_ids(rows,'Rec')) -vyka_det = fetch_details(cur, 'DOKLADD', 'ID', 'ID', ['KOD','DDGN'], get_ids(rows,'VykA')) +vyka_det = fetch_details(cur, 'DOKLADD', 'ID', 'ID', ['KOD','DDGN','BODY'], get_ids(rows,'VykA')) files_det = fetch_details(cur, 'FILES', 'ID', 'ID', ['FILENAME','DATUM'], get_ids(rows,'Files')) medlab_det = fetch_details(cur, 'HISTDOC', 'ID', 'ID', ['DATUM','TYP'], get_ids(rows,'MEDLAB')) lab_det = fetch_details(cur, 'LABVH', 'IDVH', 'IDVH', ['DATUM','CISLO'], get_ids(rows,'Lab')) @@ -86,17 +112,17 @@ hl_fill = PatternFill("solid", fgColor="2E75B6") r_fill = [PatternFill("solid", fgColor="FFFFFF"), PatternFill("solid", fgColor="DCE6F1")] BARVY_LISTU = { - 'Recepty': ('1F6B33', 'E2EFDA'), - 'Výkony': ('2E4057', 'D6E4F0'), - 'Soubory': ('7B3F00', 'FAE5D3'), - 'MedLab': ('4A235A', 'F5EEF8'), - 'Lab': ('145A32', 'D5F5E3'), - 'Očkování': ('7E5109', 'FDEBD0'), - 'Neschop.': ('922B21', 'FADBD8'), - 'Léčiva': ('1A5276', 'D6EAF8'), - 'SpecVys': ('0B5345', 'D1F2EB'), - 'Platby': ('4D5656', 'EAECEE'), - 'Ostatní': ('2C3E50', 'EBF5FB'), + 'Recepty': ('1F6B33', 'E2EFDA'), + 'Výkony': ('2E4057', 'D6E4F0'), + 'Soubory': ('7B3F00', 'FAE5D3'), + 'Žádanky': ('4A235A', 'F5EEF8'), + 'Lab výsl.': ('145A32', 'D5F5E3'), + 'Očkování': ('7E5109', 'FDEBD0'), + 'Neschop.': ('922B21', 'FADBD8'), + 'Léčiva': ('1A5276', 'D6EAF8'), + 'SpecVys': ('0B5345', 'D1F2EB'), + 'Platby': ('4D5656', 'EAECEE'), + 'Ostatní': ('2C3E50', 'EBF5FB'), } def zapis_hlavicku(ws, sloupce, sirky, barva_hex): @@ -125,7 +151,9 @@ def hyperlink_cell(ws, row_i, col_i, cil_list, cil_radek, text, barva_hex): else PatternFill("solid", fgColor=barva_hex) cell = ws.cell(row=row_i, column=col_i) cell.value = str(text) - cell.hyperlink = f'#{cil_list}!A{cil_radek}' + # Název listu s mezerou musí být v apostrofech + sheet_ref = f"'{cil_list}'" if ' ' in cil_list else cil_list + cell.hyperlink = f'#{sheet_ref}!A{cil_radek}' cell.font = Font(color="0000FF", underline='single') cell.fill = fill cell.border = ohraniceni @@ -134,53 +162,63 @@ def hyperlink_cell(ws, row_i, col_i, cil_list, cil_radek, text, barva_hex): # ── Workbook ─────────────────────────────────────────────────────────────── wb = openpyxl.Workbook() -# Pořadí listů a jejich konfigurace: (název, typ_bookmarku, detail_dict, sloupce, šířky, pk_label) LISTY = [ - ('Recepty', 'Rec', rec_det, ['Datum','Jméno','Recept','Dávkování'], [12,25,25,12], None), - ('Výkony', 'VykA', vyka_det, ['Datum','Jméno','Kód výkonu','Diagnóza'], [12,25,14,10], None), - ('Soubory', 'Files', files_det, ['Datum','Jméno','Soubor','Datum souboru'], [12,25,35,14], None), - ('MedLab', 'MEDLAB', medlab_det, ['Datum','Jméno','Typ'], [12,25,15], None), - ('Lab', 'Lab', lab_det, ['Datum','Jméno','Číslo'], [12,25,20], None), - ('Očkování', 'Ock', ock_det, ['Datum','Jméno','Datum očkování','Vakcína'], [12,25,14,30], None), - ('Neschop.', 'Nes', nes_det, ['Datum','Jméno','Od','Do'], [12,25,12,12], None), - ('Léčiva', 'Lec', lec_det, ['Datum','Jméno','Kód','Datum výkonu'], [12,25,12,14], None), - ('SpecVys', 'SpecVys', spec_det, ['Datum','Jméno','Typ vyšetření','Datum vyšetření'], [12,25,25,14], None), - ('Platby', 'PlaPac', pla_det, ['Datum','Jméno','Datum platby','Částka','Doklad'], [12,25,14,12,15], None), - ('Ostatní', None, None, ['Datum','Jméno','Typ','ID','Název'], [12,25,12,10,30], None), + ('Recepty', 'Rec', rec_det, ['Datum','Jméno','Recept','Dávkování'], [12,25,25,12], None), + ('Výkony', 'VykA', vyka_det, ['Datum','Jméno','Kód výkonu','Diagnóza','Body'], [12,25,14,10,8], None), + ('Soubory', 'Files', files_det, ['Datum','Jméno','Soubor','Datum souboru'], [12,25,35,14], None), + ('Žádanky', 'MEDLAB', medlab_det, ['Datum','Jméno','Typ'], [12,25,15], None), + ('Lab výsl.', 'Lab', lab_det, ['Datum','Jméno','Číslo'], [12,25,20], None), + ('Očkování', 'Ock', ock_det, ['Datum','Jméno','Datum očkování','Vakcína'], [12,25,14,30], None), + ('Neschop.', 'Nes', nes_det, ['Datum','Jméno','Od','Do'], [12,25,12,12], None), + ('Léčiva', 'Lec', lec_det, ['Datum','Jméno','Kód','Datum výkonu'], [12,25,12,14], None), + ('SpecVys', 'SpecVys', spec_det, ['Datum','Jméno','Typ vyšetření','Datum vyšetření'], [12,25,25,14], None), + ('Platby', 'PlaPac', pla_det, ['Datum','Jméno','Datum platby','Částka','Doklad'], [12,25,14,12,15], None), + ('Ostatní', None, None, ['Datum','Jméno','Typ','ID','Název'], [12,25,12,10,30], None), ] -# Vytvoříme listy ws_d = wb.active ws_d.title = "Dekurz" + +# List "Text dekurzu" hned za Dekurzem +ws_text = wb.create_sheet("Text dekurzu") + ws_listy = {} for nazev, *_ in LISTY: ws_listy[nazev] = wb.create_sheet(nazev) -# Záhlaví listů for nazev, typ, det, sloupce, sirky, _ in LISTY: barva_hl, _ = BARVY_LISTU[nazev] zapis_hlavicku(ws_listy[nazev], sloupce, sirky, barva_hl) ws_listy[nazev].freeze_panes = 'A2' -# Záhlaví Dekurz -nazvy_d = ['Datum', 'Čas', 'Lékař', 'Jméno', 'Rodné číslo', 'Pojišťovna'] + TOP_TYPY + ['Ostatní'] -sirky_d = [12, 8, 8, 25, 14, 12 ] + [8]*10 + [8] +# Záhlaví listu "Text dekurzu" +zapis_hlavicku(ws_text, + ['Datum', 'Čas', 'Lékař', 'Jméno', 'Rodné číslo', 'Text dekurzu'], + [12, 8, 8, 25, 14, 100], + '2E75B6') +ws_text.freeze_panes = 'A2' +row_ptr_text = 2 + +# Zobrazované názvy sloupců pro TOP_TYPY (stejné pořadí) +NAZVY_TYPY = ['VykA', 'Rec', 'Files', 'Žádanky', 'Lab výsl.', 'Ock', 'Nes', 'Lec', 'SpecVys', 'PlaPac'] + +# Záhlaví Dekurz – sloupce A–R +nazvy_d = ['Datum', 'Čas', 'Lékař', 'Jméno', 'Rodné číslo', 'Pojišťovna'] + ['HodVyk'] + NAZVY_TYPY + ['Ostatní'] +sirky_d = [12, 8, 8, 25, 14, 12 ] + [10] + [38, 8, 8, 8, 8, 8, 8, 8, 8, 8] + [8] zapis_hlavicku(ws_d, nazvy_d, sirky_d, '2E75B6') ws_d.freeze_panes = 'A2' -ws_d.auto_filter.ref = f"A1:Q{len(rows)+1}" +ws_d.auto_filter.ref = f"A1:R{len(rows)+1}" -# Aktuální řádek pro každý list row_ptr = {nazev: 2 for nazev, *_ in LISTY} # ── Plnění dat ───────────────────────────────────────────────────────────── def get_det_hodnoty(typ, rid, datum, jmeno_cel): - """Vrátí seznam hodnot pro řádek detailního listu.""" if typ == 'Rec': d = rec_det.get(rid, ('', '')) return [datum, jmeno_cel, d[0] or '', d[1] or ''] elif typ == 'VykA': - d = vyka_det.get(rid, ('', '')) - return [datum, jmeno_cel, d[0] or '', (d[1] or '').strip()] + d = vyka_det.get(rid, ('', '', 0)) + return [datum, jmeno_cel, d[0] or '', (d[1] or '').strip(), d[2] or 0] elif typ == 'Files': d = files_det.get(rid, ('', '')) return [datum, jmeno_cel, d[0] or '', d[1]] @@ -208,21 +246,20 @@ def get_det_hodnoty(typ, rid, datum, jmeno_cel): return [] ZAROVNANI = { - 'Recepty': ['left','left','left','center'], - 'Výkony': ['left','left','center','center'], - 'Soubory': ['left','left','left','left'], - 'MedLab': ['left','left','center'], - 'Lab': ['left','left','center'], - 'Očkování': ['left','left','left','left'], - 'Neschop.': ['left','left','left','left'], - 'Léčiva': ['left','left','center','left'], - 'SpecVys': ['left','left','left','left'], - 'Platby': ['left','left','left','right','center'], - 'Ostatní': ['left','left','center','center','left'], + 'Recepty': ['left','left','left','center'], + 'Výkony': ['left','left','center','center','right'], + 'Soubory': ['left','left','left','left'], + 'Žádanky': ['left','left','center'], + 'Lab výsl.': ['left','left','center'], + 'Očkování': ['left','left','left','left'], + 'Neschop.': ['left','left','left','left'], + 'Léčiva': ['left','left','center','left'], + 'SpecVys': ['left','left','left','left'], + 'Platby': ['left','left','left','right','center'], + 'Ostatní': ['left','left','center','center','left'], } -for row_i, (datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_typ, ids_ostatni) in enumerate(rows, start=2): - # Ohraničení řádku Dekurz +for row_i, (datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_typ, ids_ostatni, text_dekurzu) in enumerate(rows, start=2): fill_d = r_fill[row_i % 2] for col_i in range(1, len(nazvy_d) + 1): ws_d.cell(row=row_i, column=col_i).fill = fill_d @@ -232,20 +269,30 @@ for row_i, (datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_ty ws_d.cell(row=row_i, column=2, value=str(cas)[:5] if cas else '').alignment = Alignment(horizontal='center') ws_d.cell(row=row_i, column=3, value=zkratka or '').alignment = Alignment(horizontal='center') ws_d.cell(row=row_i, column=4, value=jmeno_cel) - ws_d.cell(row=row_i, column=5, value=rodcis or '') + # Sloupec 5 – Rodné číslo jako hyperlink na list "Text dekurzu" + hyperlink_cell(ws_d, row_i, 5, 'Text dekurzu', row_ptr_text, rodcis or '', 'DCE6F1') ws_d.cell(row=row_i, column=6, value=poj or '').alignment = Alignment(horizontal='center') - # Sloupce bookmarků + # Sloupec G – HodVyk (součet bodů všech výkonů dekurzu) + hodvyk = sum((vyka_det.get(rid, ('', '', 0))[2] or 0) for rid in ids_by_typ['VykA']) + cell_hv = ws_d.cell(row=row_i, column=7, value=hodvyk if hodvyk else '') + cell_hv.alignment = Alignment(horizontal='center') + for col_off, (typ, pocet) in enumerate(zip(TOP_TYPY, top)): - col_i = 7 + col_off + col_i = 8 + col_off if pocet == 0: continue - # Najdi název listu pro tento typ nazev_listu = next((n for n, t, *_ in LISTY if t == typ), None) if nazev_listu and ids_by_typ[typ]: _, barva_ll = BARVY_LISTU[nazev_listu] - hyperlink_cell(ws_d, row_i, col_i, nazev_listu, row_ptr[nazev_listu], pocet, barva_ll[1:] if len(barva_ll) > 6 else 'DCE6F1') - # Zapiš řádky na detailní list + # Pro výkony (VykA) přidej kódy do závorky + if typ == 'VykA': + kody = [str(vyka_det.get(rid, ('',))[0] or '').strip() for rid in ids_by_typ[typ]] + kody_str = ', '.join(k for k in kody if k) + display_text = f"{pocet} ({kody_str})" if kody_str else pocet + else: + display_text = pocet + hyperlink_cell(ws_d, row_i, col_i, nazev_listu, row_ptr[nazev_listu], display_text, barva_ll[1:] if len(barva_ll) > 6 else 'DCE6F1') ws_det = ws_listy[nazev_listu] barva_hl, barva_r = BARVY_LISTU[nazev_listu] for rid in ids_by_typ[typ]: @@ -256,17 +303,32 @@ for row_i, (datum, cas, zkratka, jmeno_cel, rodcis, poj, top, ostatni, ids_by_ty else: ws_d.cell(row=row_i, column=col_i, value=pocet).alignment = Alignment(horizontal='center') - # Ostatní if ostatni: ws_det = ws_listy['Ostatní'] barva_hl, barva_r = BARVY_LISTU['Ostatní'] - hyperlink_cell(ws_d, row_i, 17, 'Ostatní', row_ptr['Ostatní'], ostatni, barva_r) + hyperlink_cell(ws_d, row_i, 18, 'Ostatní', row_ptr['Ostatní'], ostatni, barva_r) for typ, rid, nazev in ids_ostatni: zapis_radek(ws_det, row_ptr['Ostatní'], [datum, jmeno_cel, typ, rid, nazev], ZAROVNANI['Ostatní'], barva_r) row_ptr['Ostatní'] += 1 + # Zápis do listu "Text dekurzu" + fill_t = r_fill[row_ptr_text % 2] + for col_i in range(1, 7): + ws_text.cell(row=row_ptr_text, column=col_i).fill = fill_t + ws_text.cell(row=row_ptr_text, column=col_i).border = ohraniceni + c1 = ws_text.cell(row=row_ptr_text, column=1, value=datum) + c1.number_format = 'DD.MM.YYYY' + c1.alignment = Alignment(horizontal='left', vertical='center') + ws_text.cell(row=row_ptr_text, column=2, value=str(cas)[:5] if cas else '').alignment = Alignment(horizontal='center', vertical='center') + ws_text.cell(row=row_ptr_text, column=3, value=zkratka or '').alignment = Alignment(horizontal='center', vertical='center') + ws_text.cell(row=row_ptr_text, column=4, value=jmeno_cel).alignment = Alignment(horizontal='left', vertical='center') + ws_text.cell(row=row_ptr_text, column=5, value=rodcis or '').alignment = Alignment(horizontal='left', vertical='center') + cell_txt = ws_text.cell(row=row_ptr_text, column=6, value=text_dekurzu) + cell_txt.alignment = Alignment(horizontal='left', vertical='top', wrap_text=True) + row_ptr_text += 1 + # Autofiltr na detailních listech for nazev, *_ in LISTY: ws = ws_listy[nazev]