z230
This commit is contained in:
@@ -0,0 +1,379 @@
|
|||||||
|
import os
|
||||||
|
import fdb
|
||||||
|
import csv,time,pandas as pd
|
||||||
|
import openpyxl
|
||||||
|
|
||||||
|
|
||||||
|
PathToSaveCSV=r"z:\Dropbox\Ordinace\Reporty"
|
||||||
|
timestr = time.strftime("%Y-%m-%d %H-%M-%S ")
|
||||||
|
CSVname="Pacienti.xlsx"
|
||||||
|
|
||||||
|
# ================= DELETE OLD REPORTS (KEEP TODAY) ==================
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
today = datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
for fname in os.listdir(PathToSaveCSV):
|
||||||
|
if fname.endswith("Pacienti.xlsx"):
|
||||||
|
file_date = fname[:10] # first 10 chars = YYYY-MM-DD
|
||||||
|
if file_date != today: # delete only older files
|
||||||
|
try:
|
||||||
|
os.remove(os.path.join(PathToSaveCSV, fname))
|
||||||
|
print(f"🗑️ Deleted old report: {fname}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Could not delete {fname}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
con = fdb.connect(
|
||||||
|
host='192.168.1.10', database=r'm:\MEDICUS\data\medicus.FDB',
|
||||||
|
user='sysdba', password='masterkey',charset='WIN1250')
|
||||||
|
|
||||||
|
#Server=192.168.1.10
|
||||||
|
#Path=M:\Medicus\Data\Medicus.fdb
|
||||||
|
|
||||||
|
# Create a Cursor object that operates in the context of Connection con:
|
||||||
|
cur = con.cursor()
|
||||||
|
|
||||||
|
# import openpyxl module
|
||||||
|
import openpyxl
|
||||||
|
import xlwings as xw
|
||||||
|
wb = openpyxl.Workbook()
|
||||||
|
sheet = wb.active
|
||||||
|
# wb.save("sample.xlsx")
|
||||||
|
|
||||||
|
|
||||||
|
#Načtení očkování registrovaných pacientů
|
||||||
|
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")
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.title="Očkování"
|
||||||
|
sheet.append(["Rodne cislo","Prijmeni","Jmeno","Datum ockovani","Kod MZ","Sarze","Latka","Nazev","Expirace"])
|
||||||
|
#nacteno jsou ockovani
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Načtení registrovaných pacientů
|
||||||
|
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")
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
wb.create_sheet('Registrovani',0)
|
||||||
|
sheet=wb['Registrovani']
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Prijmeni","Jmeno","Datum registrace","ID pacienta","Pojistovna"])
|
||||||
|
#nacteno jsou registrovani
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
|
||||||
|
#Načtení receptů
|
||||||
|
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"""
|
||||||
|
)
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
wb.create_sheet('Recepty',0)
|
||||||
|
sheet=wb['Recepty']
|
||||||
|
|
||||||
|
sheet.title="Recepty"
|
||||||
|
sheet.append(["Rodné číslo","Jméno","Datum vystavení","Název leku","Poč.","Op.","Úhr.","Da signa","Notifikace","eRECEPT","Vystavil","ATC","Cena pojišťovna","Cena pacient"])
|
||||||
|
#nacteno jsou ockovani
|
||||||
|
for row in nacteno:
|
||||||
|
try:
|
||||||
|
sheet.append(row)
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Načtení vykony vsech
|
||||||
|
cur.execute("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 (datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null) order by dokladd.datose desc,dokladd.rodcis")
|
||||||
|
|
||||||
|
wb.create_sheet('Vykony',0)
|
||||||
|
sheet=wb['Vykony']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum vykonu","Kod","Pocet","Dg.","Body","Nazev"])
|
||||||
|
#nacteno jsou ockovani
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Načtení neschopenek
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
def pocet_dni(zacnes,konnes,pracne):
|
||||||
|
dnes=datetime.date.today()
|
||||||
|
if pracne=='A':
|
||||||
|
return (dnes-zacnes).days
|
||||||
|
if pracne=='N' and zacnes is not None and konnes is not None and zacnes<=konnes:
|
||||||
|
return (konnes-zacnes).days
|
||||||
|
else:
|
||||||
|
return "NA"
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
|
||||||
|
tmpnacteno_vse=[]
|
||||||
|
nacteno_vse=cur.fetchall()
|
||||||
|
|
||||||
|
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 and pracne='A'"
|
||||||
|
"order by datnes desc")
|
||||||
|
|
||||||
|
tmpnacteno_aktivni=[]
|
||||||
|
nacteno_aktivni=cur.fetchall()
|
||||||
|
|
||||||
|
for row in nacteno_vse:
|
||||||
|
tmpnacteno_vse.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],pocet_dni(row[5],row[7],row[6]),row[8],row[9],row[10]))
|
||||||
|
|
||||||
|
for row in nacteno_aktivni:
|
||||||
|
(tmpnacteno_aktivni.append((row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],pocet_dni(row[5],row[7],row[6]),row[8],row[9],row[10])))
|
||||||
|
|
||||||
|
wb.create_sheet('Neschopenky všechny',0)
|
||||||
|
sheet=wb["Neschopenky všechny"]
|
||||||
|
sheet.append(["ID pac","Rodne cislo","Jmeno","Datum neschopenky","Číslo neschopenky","Zacatek","Aktivní?","Konec","Pocet dni","Diagnoza zacatel","Diagnoza konec","Aktualizovano"])
|
||||||
|
for row in tmpnacteno_vse:
|
||||||
|
sheet.append(row)
|
||||||
|
|
||||||
|
wb.create_sheet('Neschopenky aktivní',0)
|
||||||
|
sheet=wb["Neschopenky aktivní"]
|
||||||
|
sheet.append(["ID pac","Rodne cislo","Jmeno","Datum neschopenky","Číslo neschopenky","Zacatek","Aktivní?","Konec","Pocet dni","Diagnoza zacatel","Diagnoza konec","Aktualizovano"])
|
||||||
|
for row in tmpnacteno_aktivni:
|
||||||
|
sheet.append(row)
|
||||||
|
|
||||||
|
#Načtení preventivni prohlidky
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and (dokladd.kod=1022 or dokladd.kod=1021) "
|
||||||
|
"order by datose desc")
|
||||||
|
|
||||||
|
wb.create_sheet('Preventivni prohlidky',0)
|
||||||
|
sheet=wb['Preventivni prohlidky']
|
||||||
|
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Nacteni INR
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and (dokladd.kod=01443) "
|
||||||
|
"order by datose desc")
|
||||||
|
|
||||||
|
wb.create_sheet('INR',0)
|
||||||
|
sheet=wb['INR']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Nacteni CRP
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and (dokladd.kod=02230 or dokladd.kod=09111) "
|
||||||
|
"order by datose desc,dokladd.rodcis,dokladd.kod")
|
||||||
|
|
||||||
|
wb.create_sheet('CRP',0)
|
||||||
|
sheet=wb['CRP']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
|
||||||
|
#Nacteni Holter
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and (dokladd.kod=17129) "
|
||||||
|
"order by datose desc,dokladd.rodcis,dokladd.kod")
|
||||||
|
|
||||||
|
wb.create_sheet('Holter',0)
|
||||||
|
sheet=wb['Holter']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Nacteni prostata
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and (dokladd.kod=01130 or dokladd.kod=01131 or dokladd.kod=01132 or dokladd.kod=01133 or dokladd.kod=01134) "
|
||||||
|
"order by datose desc,dokladd.rodcis,dokladd.kod")
|
||||||
|
|
||||||
|
wb.create_sheet('Prostata',0)
|
||||||
|
sheet=wb['Prostata']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Nacteni TOKS
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and "
|
||||||
|
"(dokladd.kod=15118 or dokladd.kod=15119 or dokladd.kod=15120 or dokladd.kod=15121) "
|
||||||
|
"order by datose desc,dokladd.rodcis,dokladd.kod")
|
||||||
|
|
||||||
|
wb.create_sheet('TOKS',0)
|
||||||
|
sheet=wb['TOKS']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Nacteni COVID
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and "
|
||||||
|
"(dokladd.kod=01306) "
|
||||||
|
"order by datose desc,dokladd.rodcis,dokladd.kod")
|
||||||
|
|
||||||
|
wb.create_sheet('COVID',0)
|
||||||
|
sheet=wb['COVID']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
#Nacteni Streptest
|
||||||
|
cur.execute("select all 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 "
|
||||||
|
"((datose>=vykony.platiod and datose<=vykony.platido) OR (datose>=vykony.platiod and vykony.platido is null)) and "
|
||||||
|
"(dokladd.kod=02220) "
|
||||||
|
"order by datose desc,dokladd.rodcis,dokladd.kod")
|
||||||
|
|
||||||
|
wb.create_sheet('Streptest',0)
|
||||||
|
sheet=wb['Streptest']
|
||||||
|
|
||||||
|
nacteno=cur.fetchall()
|
||||||
|
print(len(nacteno))
|
||||||
|
|
||||||
|
sheet.append(["Rodne cislo","Jmeno","Datum","Kod","Název","Dg.","Body"])
|
||||||
|
|
||||||
|
for row in nacteno:
|
||||||
|
sheet.append(row)
|
||||||
|
|
||||||
|
|
||||||
|
# autofilter
|
||||||
|
for ws in wb.worksheets:
|
||||||
|
# Get the maximum number of rows and columns
|
||||||
|
max_row = ws.max_row
|
||||||
|
max_column = ws.max_column
|
||||||
|
ws.auto_filter.ref = f"A1:{openpyxl.utils.get_column_letter(max_column)}{max_row}"
|
||||||
|
# ws.auto_filter.ref = ws.dimensions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
wb.save(os.path.join(PathToSaveCSV ,timestr+CSVname))
|
||||||
|
|
||||||
|
|
||||||
|
# Tento modul je pouze na autofit jednotlivych sloupcu na vsech listech workbooku
|
||||||
|
file = os.path.join(PathToSaveCSV ,timestr+CSVname)
|
||||||
|
with xw.App(visible=False) as app:
|
||||||
|
wb = xw.Book(file)
|
||||||
|
for sheet in range(len(wb.sheets)):
|
||||||
|
ws = wb.sheets[sheet]
|
||||||
|
ws.autofit()
|
||||||
|
|
||||||
|
# centrování receptů
|
||||||
|
sheet = wb.sheets['Recepty']
|
||||||
|
for sloupec in ["C:C", "E:E", "F:F", "G:G", "I:I", "M:M", "N:N"]:
|
||||||
|
sheet.range(sloupec).api.HorizontalAlignment = 3 # 3 = Center
|
||||||
|
|
||||||
|
|
||||||
|
wb.save()
|
||||||
|
wb.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
# MedicusWithClaudeKomplexniReport – CLAUDE_NOTES
|
||||||
|
|
||||||
|
## Co skript dělá
|
||||||
|
|
||||||
|
`komplexni_report.py` generuje komplexní Excel přehled ordinace.
|
||||||
|
Soubor se ukládá do `u:\Dropbox\!!!Days\Downloads Z230\YYYY-MM-DD_HH-MM-SS_Pacienti.xlsx`.
|
||||||
|
Předchozí verze (`*Pacienti.xlsx`) se před zápisem automaticky smažou.
|
||||||
|
|
||||||
|
## Spuštění
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\Python\python.exe komplexni_report.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Trvá cca **10 minut** (kvůli xlwings autofit přes celý Excel).
|
||||||
|
Spouští se automaticky v noci → nevadí.
|
||||||
|
|
||||||
|
## Připojení k DB
|
||||||
|
|
||||||
|
```python
|
||||||
|
fdb.connect(
|
||||||
|
host='localhost',
|
||||||
|
database=r'c:\MEDICUS 3\data\medicus.FDB',
|
||||||
|
user='sysdba', password='masterkey', charset='WIN1250'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Závislosti
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install fdb openpyxl xlwings extract-msg beautifulsoup4 python-dateutil
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Listy v Excelu (pořadí)
|
||||||
|
|
||||||
|
| List | Zdroj | Popis |
|
||||||
|
|---|---|---|
|
||||||
|
| `Registrovani` | registr + kar | Aktivní registrovaní pacienti |
|
||||||
|
| `Očkování` | ockzaz + registr + kar | Záznamy o očkování registrovaných |
|
||||||
|
| `Recepty` | recept + recept_epodani + kar | Všechny recepty, eRECEPT čísla, ceny |
|
||||||
|
| `Vykony` | dokladd + kar + vykony | Všechny výkony (s platným číselníkem) |
|
||||||
|
| `Neschopenky všechny` | nes + kar | Všechny neschopenky |
|
||||||
|
| `Neschopenky aktivní` | nes + kar | Pouze aktivní (pracne='A') |
|
||||||
|
| `Preventivni prohlidky` | dokladd + vykony | Kódy 1021, 1022 |
|
||||||
|
| `INR` | dokladd + vykony | Kód 1443 |
|
||||||
|
| `CRP` | dokladd + vykony | Kódy 2230, 9111 |
|
||||||
|
| `Holter` | dokladd + vykony | Kód 17129 |
|
||||||
|
| `Prostata` | dokladd + vykony | Kódy 1130–1134 |
|
||||||
|
| `TOKS` | dokladd + vykony | Kódy 15118–15121 |
|
||||||
|
| `COVID` | dokladd + vykony | Kód 1306 |
|
||||||
|
| `Streptest` | dokladd + vykony | Kód 2220 |
|
||||||
|
| `Posudky řidičák` | HISTDOC (TYP=MOTORVO) + KAR | Ruční posudky k řízení MV |
|
||||||
|
| `ePosudky registr` | HISTDOC (TYP=EPOSMRO) + HISTDOC_EPOSUDEK + KAR | Elektronická podání do centrálního registru |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pomocné funkce
|
||||||
|
|
||||||
|
### `sanitize(val)`
|
||||||
|
Opraví znaky neplatné pro Excel:
|
||||||
|
- `µ` → `u`
|
||||||
|
- řídící znaky (ord < 32, kromě tab/LF/CR) → `_`
|
||||||
|
- náhradní znaky Unicode (0xFFFE, 0xFFFF, surrogáty) → `_`
|
||||||
|
|
||||||
|
Použito ve všech listech kde hrozí problematická data z DB.
|
||||||
|
|
||||||
|
### `fmt(val)`
|
||||||
|
Vrátí `''` pro None, jinak zavolá `sanitize()`.
|
||||||
|
|
||||||
|
### `add_vykony_sheet(sheet_name, kody)`
|
||||||
|
Helper pro listy s výkony. Přijme název listu a seznam kódů výkonů.
|
||||||
|
SQL: `dokladd JOIN kar JOIN vykony WHERE kod IN (...) AND platnost kódu platí`.
|
||||||
|
Řazení: datum DESC, rodcis, kod.
|
||||||
|
|
||||||
|
### `pocet_dni(zacnes, konnes, pracne)`
|
||||||
|
Výpočet délky neschopenky:
|
||||||
|
- `pracne='A'` (aktivní) → dny od začátku do dnes
|
||||||
|
- `pracne='N'` → dny od začátku do konce
|
||||||
|
- jinak → `"NA"`
|
||||||
|
|
||||||
|
### `parse_data(data_str)`
|
||||||
|
Parsuje `key=value` text z pole `HISTDOC.DATA` do slovníku.
|
||||||
|
Každý řádek = jeden klíč/hodnota oddělené `=`.
|
||||||
|
|
||||||
|
### `parse_date(val)`
|
||||||
|
Převede formát `D:DD.MM.YYYY` (jak ho ukládá Medicus) na `datetime.date`.
|
||||||
|
|
||||||
|
### `style_header(ws)` / `autofit_ws(ws)`
|
||||||
|
Styl záhlaví (modrý fill, bílý tučný text, centrování) a šířky sloupců (max 50 znaků).
|
||||||
|
Používají se jen na listech s posudky (ostatní listy řeší xlwings).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Listy s posudky – detail
|
||||||
|
|
||||||
|
### `Posudky řidičák` (MOTORVO)
|
||||||
|
|
||||||
|
Data jsou uložena v `HISTDOC.DATA` jako `key=value` text.
|
||||||
|
Parsovaná pole:
|
||||||
|
|
||||||
|
| Sloupec | Zdroj v DATA |
|
||||||
|
|---|---|
|
||||||
|
| PorCislo | `PorCislo` nebo `HISTDOC.PORCISLO` |
|
||||||
|
| DatumVyd | `DatumVyd` (formát `D:DD.MM.YYYY`) |
|
||||||
|
| DatKonec | `DatKonec` (formát `D:DD.MM.YYYY`) |
|
||||||
|
| DruhProh | `DruhProh` |
|
||||||
|
| Posouzeni | odvozeno z `Posouzeni`, `Posouzeni2`, `ZpusobPodminka` |
|
||||||
|
| ZpusobPodminka | `ZpusobPodminka` |
|
||||||
|
| SkupinaPodminka | `SkupinaPodminka` |
|
||||||
|
| Skupiny | `ZpusobJe` |
|
||||||
|
|
||||||
|
**Logika Posouzeni:**
|
||||||
|
- `Posouzeni2 = T` → `nezpůsobilý`
|
||||||
|
- `ZpusobPodminka = B:1` → `způsobilý s podmínkou`
|
||||||
|
- `Posouzeni = T` → `způsobilý`
|
||||||
|
|
||||||
|
**Sloupec ePosudek:**
|
||||||
|
`ANO` pokud existuje záznam v HISTDOC s `TYP='EPOSMRO'` pro stejného pacienta (IDPACI) a stejné datum.
|
||||||
|
Párování: `(IDPACI, DATUM)` – přímá FK vazba mezi MOTORVO a EPOSMRO neexistuje.
|
||||||
|
Buňka s ANO je zelená (fill + font).
|
||||||
|
|
||||||
|
**Zebra pruhování:** liché řádky bílé, sudé světle modré (`DCE6F1`).
|
||||||
|
|
||||||
|
### `ePosudky registr` (EPOSMRO)
|
||||||
|
|
||||||
|
Elektronická podání do centrálního registru způsobilosti.
|
||||||
|
Stát tuto funkci zavedl přibližně od aktualizace Medicusu (03/2026).
|
||||||
|
|
||||||
|
Data parsovaná z `HISTDOC.DATA`:
|
||||||
|
|
||||||
|
| Sloupec | Zdroj v DATA |
|
||||||
|
|---|---|
|
||||||
|
| DatumVyd | `DatumVystaveni` |
|
||||||
|
| DatKonec | `PlatnostDo` |
|
||||||
|
| DruhProhlidky | `DruhProhlidkyNazev` |
|
||||||
|
| DruhPosudku | `DruhPosudkuNazev` |
|
||||||
|
| Vysledek | `VysledekNazev` |
|
||||||
|
| StavPosudku | `StavPosudkuNazev` |
|
||||||
|
| TypAkce | `TypAkceNazev` |
|
||||||
|
|
||||||
|
Stavová pole z `HISTDOC_EPOSUDEK`:
|
||||||
|
- `ID_PODANI` – ID podání do registru
|
||||||
|
- `ODESLANO` – timestamp odeslání
|
||||||
|
- `STATUS_ODESL` – stav odpovědi z registru (`O` = odesláno)
|
||||||
|
|
||||||
|
**Zneplatnění:** `StavPosudku = zneplatneny` = lékař aktivně odvolal způsobilost
|
||||||
|
(např. pacient prodělal mrtvici, epileptický záchvat atp.).
|
||||||
|
Zneplatnění je samostatný EPOSMRO záznam, ne modifikace původního.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## xlwings – závěrečný krok
|
||||||
|
|
||||||
|
Po `wb.save()` se soubor otevře přes xlwings (vyžaduje plný Excel):
|
||||||
|
1. `sheet.autofit()` na všech listech – správné šířky sloupců
|
||||||
|
2. Na listu `Recepty`: centrování sloupců C, E, F, G, I, M, N
|
||||||
|
3. `wb_xw.save()` + zavření
|
||||||
|
|
||||||
|
xlwings je nutný pro spolehlivý autofit (openpyxl ho neumí přesně).
|
||||||
|
Trvá ~10 minut, spouští se v noci.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pořadí zpracování (pro debugování)
|
||||||
|
|
||||||
|
```
|
||||||
|
DB connect
|
||||||
|
→ smazání starých souborů
|
||||||
|
→ SQL dotazy (Registrovani, Očkování, Recepty, Výkony, Neschopenky)
|
||||||
|
→ add_vykony_sheet × 8
|
||||||
|
→ MOTORVO + EPOSMRO listy (s parsováním DATA)
|
||||||
|
→ autofilter na všech listech
|
||||||
|
→ con.close() + wb.save()
|
||||||
|
→ xlwings autofit + centrování
|
||||||
|
→ Hotovo.
|
||||||
|
```
|
||||||
|
|
||||||
|
Print výstup v konzoli ukazuje počty řádků každého listu – užitečné pro kontrolu.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rozšíření v budoucnu
|
||||||
|
|
||||||
|
- Přidat další typy posudků (pracovní, vstupní, sportovní...) ze `VS_POSUDKY`
|
||||||
|
- Případně sledovat stav podání EPOSMRO v čase (datum odeslání vs. datum posudku)
|
||||||
|
- Automatické spouštění přes Windows Task Scheduler (jako `faktury_report.py`)
|
||||||
@@ -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.")
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
# MedicusWithClaudePosudek – poznámky pro Clauda
|
||||||
|
|
||||||
|
## O co jde
|
||||||
|
|
||||||
|
Lékařské posudky vystavované MUDr. Buzalkovou. Prozatím řešíme posudky k řízení motorových vozidel.
|
||||||
|
|
||||||
|
Nový zákon ukládá povinnost odesílat posudky k řízení do **centrálního registru** – tuto funkci Medicus přidal v aktualizaci z konce března 2026.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tabulky
|
||||||
|
|
||||||
|
### HISTDOC – hlavní tabulka pro všechny posudky
|
||||||
|
|
||||||
|
Všechny posudky jsou záznamy v `HISTDOC`, lišící se hodnotou sloupce `TYP`.
|
||||||
|
|
||||||
|
Klíčové sloupce:
|
||||||
|
| Sloupec | Popis |
|
||||||
|
|---|---|
|
||||||
|
| `ID` | primární klíč |
|
||||||
|
| `TYP` | typ dokumentu (viz níže) |
|
||||||
|
| `DATUM` | datum vystavení posudku |
|
||||||
|
| `IDPACI` | FK → KAR.IDPAC (pacient) |
|
||||||
|
| `DATA` | obsah posudku – text ve formátu key=value (viz níže) |
|
||||||
|
| `PORCISLO` | pořadové číslo posudku (= PorCislo v DATA) |
|
||||||
|
| `STAV` | stav záznamu (Z = zavřeno) |
|
||||||
|
| `PRINTED` | T/F – byl vytištěn |
|
||||||
|
| `IDUZIV` | FK → UZIVATEL.IDUZI – kdo vystavil (4 = MUDr. Buzalková) |
|
||||||
|
| `CREATED` | timestamp vytvoření záznamu |
|
||||||
|
|
||||||
|
**Vazba:** žádná přímá vazba na jiné tabulky (vyšetření, dekurz apod.) – posudek je svébytný dokument.
|
||||||
|
|
||||||
|
### TYP hodnoty relevantní pro posudky řidičů
|
||||||
|
|
||||||
|
| TYP | Popis | Počet (k 2026-03-31) |
|
||||||
|
|---|---|---|
|
||||||
|
| `MOTORVO` | ruční posudek k řízení motorových vozidel | 1530 |
|
||||||
|
| `EPOSMRO` | elektronické podání posudku do centrálního registru | 2 |
|
||||||
|
|
||||||
|
Ostatní typy posudků v HISTDOC (pro referenci):
|
||||||
|
- `ZBROJPR`, `ZBROJP2` – zbrojní průkaz
|
||||||
|
- `ZPUPRN` – způsobilost pro práci
|
||||||
|
- `ZDRSTA3`–`ZDRSTA5`, `ZDRSTAV`, `ZDRINF` – zdravotní stav (různé varianty)
|
||||||
|
- ... (celkem desítky typů)
|
||||||
|
|
||||||
|
### HISTDOC_EPOSUDEK – evidence odeslání do registru
|
||||||
|
|
||||||
|
Doplňková tabulka k EPOSMRO záznamům v HISTDOC.
|
||||||
|
|
||||||
|
| Sloupec | Popis |
|
||||||
|
|---|---|
|
||||||
|
| `ID_HISTDOC` | FK → HISTDOC.ID (záznam EPOSMRO) |
|
||||||
|
| `ID_PODANI` | UUID přidělené centrálním registrem |
|
||||||
|
| `ODESLANO` | timestamp odeslání |
|
||||||
|
| `STATUS` | O = odesláno |
|
||||||
|
| `VERZE` | verze záznamu (base64 interní hodnota) |
|
||||||
|
|
||||||
|
### VS_POSUDKY – prázdná, zatím nepoužívaná
|
||||||
|
|
||||||
|
Sloupce: ID, IDPAC, DATA (BLOB), DATUM, POSTYPE. Pravděpodobně připravena pro budoucí využití.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow: ruční posudek → elektronické podání
|
||||||
|
|
||||||
|
1. Lékař v Medicusu vyplní posudek → vznikne `HISTDOC` TYP=`MOTORVO`
|
||||||
|
2. Medicus automaticky odešle do centrálního registru → vznikne `HISTDOC` TYP=`EPOSMRO` + záznam v `HISTDOC_EPOSUDEK`
|
||||||
|
3. Oba záznamy mají stejné `IDPACI` + `DATUM` → podle toho je párujeme
|
||||||
|
|
||||||
|
Příklad (pacient Vráček, 30.3.2026):
|
||||||
|
- HISTDOC ID=34743, TYP=MOTORVO, CREATED=13:12
|
||||||
|
- HISTDOC ID=34746, TYP=EPOSMRO, CREATED=13:21
|
||||||
|
- HISTDOC_EPOSUDEK: STATUS=O, ODESLANO=13:21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Formát DATA (key=value) – MOTORVO
|
||||||
|
|
||||||
|
```
|
||||||
|
JmenoPac=Radomil Vráček
|
||||||
|
DatNar=D:27.03.1956
|
||||||
|
Prukaz=207069669 ← číslo řidičského průkazu
|
||||||
|
DatKonec=D:30.03.2028 ← platnost posudku do
|
||||||
|
DatumVyd=D:30.03.2026 ← datum vydání
|
||||||
|
Bydliste=K Šafránce 507/16, 19000 Praha 9-Střížkov
|
||||||
|
DruhProh=periodická ← druh prohlídky
|
||||||
|
Posouzeni=T ← T = způsobilý (F = nezpůsobilý?)
|
||||||
|
Posouzeni2=F ← T = nezpůsobilý (druhá volba)
|
||||||
|
ZpusobJe=B:0 ← skupiny bez podmínky
|
||||||
|
ZpusobPodminka=B:1 ← B:1 = má podmínku
|
||||||
|
SkupinaPodminka=sk. B brýle
|
||||||
|
PorCislo=2600037
|
||||||
|
KonecDleZakona=D
|
||||||
|
DatumPrevzeti=D:30.03.2026
|
||||||
|
```
|
||||||
|
|
||||||
|
**Výsledek posouzení** (kombinace Posouzeni + Posouzeni2 + ZpusobPodminka):
|
||||||
|
- `Posouzeni=T` + `Posouzeni2=F` + `ZpusobPodminka=B:0` → způsobilý
|
||||||
|
- `Posouzeni=T` + `Posouzeni2=F` + `ZpusobPodminka=B:1` → způsobilý s podmínkou
|
||||||
|
- `Posouzeni=T` + `Posouzeni2=T` → nezpůsobilý
|
||||||
|
|
||||||
|
## Formát DATA (key=value) – EPOSMRO
|
||||||
|
|
||||||
|
```
|
||||||
|
Lekar=MUDr. Michaela Buzalková
|
||||||
|
KRZPID=130153584 ← ID lékaře v registru
|
||||||
|
ICO=68366370
|
||||||
|
ICP=09305001
|
||||||
|
Pacient=Radomil Vráček
|
||||||
|
RID=8705636888 ← číslo řidičáku
|
||||||
|
DatumNarozeni=D:27.03.1956
|
||||||
|
StavPosudkuKodVerze=zneplatneny|1.0.0
|
||||||
|
StavPosudkuNazev=Zneplatněný ← stav posudku v registru
|
||||||
|
TypAkceNazev=vytvoření
|
||||||
|
TypAkceKodVerze=akce_ro_1|1.0.0
|
||||||
|
DruhProhlidkyNazev=pravidelná
|
||||||
|
DruhProhlidkyKodVerze=Pravidelna|1.0.0
|
||||||
|
DruhPosudkuNazev=řidičské oprávnění pro seniory
|
||||||
|
DruhPosudkuKodVerze=SenioriRo|1.0.0
|
||||||
|
SkupinaZadatelRidicNazev=skupina 1
|
||||||
|
SkupinyRidicskehoOpravneniSeznam=B
|
||||||
|
HarmonizovaneNarodniKody=$:~HNK1:011:01.01 Brýle5:01.012:HK1:B0: ← kódy omezení (brýle)
|
||||||
|
VysledekKodVerze=ZpusobilySPodminkou|1.0.0
|
||||||
|
VysledekNazev=způsobilý s podmínkou
|
||||||
|
DatumVystaveni=D:30.03.2026
|
||||||
|
PlatnostDo=D:30.03.2028
|
||||||
|
```
|
||||||
|
|
||||||
|
**StavPosudku = "Zneplatněný"** neznamená chybu – jde o akci, kdy lékař odvolá způsobilost pacienta (např. po mrtvici, epileptickém záchvatu apod.). Medicus pak odešle do registru zneplatnění existujícího posudku.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Soubory v projektu
|
||||||
|
|
||||||
|
- `posudky_report.py` – generuje Excel s listy MOTORVO a EPOSMRO
|
||||||
|
- `CLAUDE_NOTES.md` – tento soubor
|
||||||
|
|
||||||
|
## Report (posudky_report.py)
|
||||||
|
|
||||||
|
- Výstup: `u:\Dropbox\!!!Days\Downloads Z230\YYYY-MM-DD_HH-MM-SS_Přehled posudků řidičák.xlsx`
|
||||||
|
- Maže předchozí verzi před zápisem nové
|
||||||
|
- List MOTORVO: 1530 záznamů, sloupec `ePosudek` = ANO (zeleně) / NE podle toho, zda byl odeslán ePosudek (párování IDPACI + DATUM)
|
||||||
|
- List EPOSMRO: 2 záznamy, detail elektronického podání
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
import fdb
|
||||||
|
import openpyxl
|
||||||
|
from openpyxl.styles import Font, PatternFill, Alignment
|
||||||
|
from openpyxl.utils import get_column_letter
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# --- Připojení ---
|
||||||
|
conn = fdb.connect(
|
||||||
|
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||||
|
user='SYSDBA', password='masterkey', charset='win1250'
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# --- Výstupní soubor ---
|
||||||
|
output_dir = r'u:\Dropbox\!!!Days\Downloads Z230'
|
||||||
|
now = datetime.now()
|
||||||
|
filename = now.strftime('%Y-%m-%d_%H-%M-%S') + '_Přehled posudků řidičák.xlsx'
|
||||||
|
output_path = os.path.join(output_dir, filename)
|
||||||
|
|
||||||
|
# --- Smazání předchozích verzí ---
|
||||||
|
for f in os.listdir(output_dir):
|
||||||
|
if f.endswith('_Přehled posudků řidičák.xlsx'):
|
||||||
|
os.remove(os.path.join(output_dir, f))
|
||||||
|
|
||||||
|
wb = openpyxl.Workbook()
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# Pomocné funkce
|
||||||
|
# =====================
|
||||||
|
|
||||||
|
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):
|
||||||
|
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 fmt(val):
|
||||||
|
if val is None:
|
||||||
|
return ''
|
||||||
|
return 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, nebo vrátí původní hodnotu."""
|
||||||
|
if val and val.startswith('D:'):
|
||||||
|
try:
|
||||||
|
return datetime.strptime(val[2:], '%d.%m.%Y').date()
|
||||||
|
except ValueError:
|
||||||
|
return val
|
||||||
|
return val
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# List 1 – MOTORVO (ruční posudky k řízení)
|
||||||
|
# =====================
|
||||||
|
|
||||||
|
ws1 = wb.active
|
||||||
|
ws1.title = 'MOTORVO'
|
||||||
|
|
||||||
|
# Množina (IDPACI, DATUM) kde existuje EPOSMRO
|
||||||
|
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
|
||||||
|
""")
|
||||||
|
raw_rows = cur.fetchall()
|
||||||
|
|
||||||
|
headers = [
|
||||||
|
'ID', 'DATUM', 'IDPACI', 'PRIJMENI', 'JMENO', 'RODCIS',
|
||||||
|
'PorCislo', 'DatumVyd', 'DatKonec', 'DruhProh',
|
||||||
|
'Posouzeni', 'ZpusobPodminka', 'SkupinaPodminka',
|
||||||
|
'Skupiny',
|
||||||
|
'ePosudek',
|
||||||
|
'STAV', 'PRINTED', 'IDUZIV', 'CREATED'
|
||||||
|
]
|
||||||
|
ws1.append(headers)
|
||||||
|
|
||||||
|
for i, row in enumerate(raw_rows, start=2):
|
||||||
|
(hid, datum, idpac, prijmeni, jmeno, rodcis,
|
||||||
|
data_blob, porcislo, stav, printed, iduziv, created) = row
|
||||||
|
|
||||||
|
data = parse_data(data_blob)
|
||||||
|
|
||||||
|
posouzeni = ''
|
||||||
|
if data.get('Posouzeni') == 'T':
|
||||||
|
if data.get('Posouzeni2') == 'T':
|
||||||
|
posouzeni = 'nezpůsobilý'
|
||||||
|
elif data.get('ZpusobPodminka') == 'B:1':
|
||||||
|
posouzeni = 'způsobilý s podmínkou'
|
||||||
|
else:
|
||||||
|
posouzeni = 'způsobilý'
|
||||||
|
|
||||||
|
skupiny = data.get('SkupinyRidicskehoOpravneniSeznam', '')
|
||||||
|
if not skupiny:
|
||||||
|
# MOTORVO nemá SkupinyRidicskehoOpravneniSeznam, zkusíme ZpusobJe
|
||||||
|
skupiny = data.get('ZpusobJe', '')
|
||||||
|
|
||||||
|
ws1.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(skupiny),
|
||||||
|
'ANO' if (idpac, datum) in eposmro_keys else 'NE',
|
||||||
|
fmt(stav),
|
||||||
|
fmt(printed),
|
||||||
|
fmt(iduziv),
|
||||||
|
fmt(created),
|
||||||
|
])
|
||||||
|
|
||||||
|
if i % 2 == 0:
|
||||||
|
for cell in ws1[i]:
|
||||||
|
cell.fill = ZEBRA_FILL
|
||||||
|
|
||||||
|
# Sloupec ePosudek – zvýraznit ANO zeleně
|
||||||
|
epos_col = headers.index('ePosudek') + 1
|
||||||
|
cell = ws1.cell(row=i, column=epos_col)
|
||||||
|
if cell.value == 'ANO':
|
||||||
|
cell.fill = GREEN_FILL
|
||||||
|
cell.font = GREEN_FONT
|
||||||
|
|
||||||
|
style_header(ws1)
|
||||||
|
ws1.freeze_panes = 'A2'
|
||||||
|
autofit(ws1)
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# List 2 – EPOSMRO (elektronická podání do registru)
|
||||||
|
# =====================
|
||||||
|
|
||||||
|
ws2 = wb.create_sheet('EPOSMRO')
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
headers2 = [
|
||||||
|
'ID', 'DATUM', 'IDPACI', 'PRIJMENI', 'JMENO', 'RODCIS',
|
||||||
|
'DatumVyd', 'DatKonec', 'DruhProhlidky', 'DruhPosudku',
|
||||||
|
'Vysledek', 'StavPosudku', 'TypAkce',
|
||||||
|
'STAV', 'CREATED',
|
||||||
|
'ID_PODANI', 'ODESLANO', 'STATUS_ODESL'
|
||||||
|
]
|
||||||
|
ws2.append(headers2)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
ws2.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 ws2[i]:
|
||||||
|
cell.fill = ZEBRA_FILL
|
||||||
|
|
||||||
|
style_header(ws2)
|
||||||
|
ws2.freeze_panes = 'A2'
|
||||||
|
autofit(ws2)
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# Uložení
|
||||||
|
# =====================
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
wb.save(output_path)
|
||||||
|
sys.stdout.buffer.write(f'Ulozeno: {output_path}\n'.encode('utf-8'))
|
||||||
|
sys.stdout.buffer.write(f'MOTORVO: {len(raw_rows)} radku, EPOSMRO: {len(epos_rows)} radku\n'.encode('utf-8'))
|
||||||
Reference in New Issue
Block a user