z230
This commit is contained in:
+161
-13
@@ -39,7 +39,9 @@ EVEN_FILL = PatternFill("solid", fgColor="EBF3FB")
|
||||
ODD_FILL = PatternFill("solid", fgColor="FFFFFF")
|
||||
NOTRCV_FILL = PatternFill("solid", fgColor="FCE4D6")
|
||||
CANCELLED_FILL = PatternFill("solid", fgColor="F2F2F2")
|
||||
OPEN_FILL = PatternFill("solid", fgColor="FFC7CE")
|
||||
OPEN_FILL = PatternFill("solid", fgColor="FFC7CE")
|
||||
OPEN_QUERY_FILL = PatternFill("solid", fgColor="FFD966")
|
||||
HYPERLINK_FONT = Font(name="Arial", size=10, color="0563C1", underline="single")
|
||||
|
||||
CENTER = Alignment(horizontal="center", vertical="center")
|
||||
LEFT = Alignment(horizontal="left", vertical="center")
|
||||
@@ -84,6 +86,33 @@ def load_data():
|
||||
return pd.DataFrame(rows, columns=cols)
|
||||
|
||||
|
||||
def load_equery_data():
|
||||
conn = mysql.connector.connect(
|
||||
host=db_config.DB_HOST, port=db_config.DB_PORT,
|
||||
user=db_config.DB_USER, password=db_config.DB_PASSWORD,
|
||||
database=db_config.DB_NAME,
|
||||
)
|
||||
sql = """
|
||||
SELECT site_code, investigator_name, subject, visit,
|
||||
accession, visit_collection_date, equery_id,
|
||||
create_date, response_datetime, issue_type, status,
|
||||
time_before_response, user_name, study_role
|
||||
FROM covance_equeries
|
||||
WHERE import_id = (
|
||||
SELECT MAX(import_id) FROM iwrs_import
|
||||
WHERE study = %s AND report_type = 'covance_equeries'
|
||||
)
|
||||
ORDER BY site_code ASC, create_date DESC
|
||||
"""
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(sql, (STUDY,))
|
||||
cols = [d[0] for d in cursor.description]
|
||||
rows = cursor.fetchall()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return pd.DataFrame(rows, columns=cols)
|
||||
|
||||
|
||||
def load_kit_data():
|
||||
conn = mysql.connector.connect(
|
||||
host=db_config.DB_HOST, port=db_config.DB_PORT,
|
||||
@@ -137,7 +166,9 @@ def write_title(ws, text, ncols):
|
||||
|
||||
# ── sheet 1: Přehled ─────────────────────────────────────────────────────────
|
||||
|
||||
def write_prehled(wb, df):
|
||||
def write_prehled(wb, df, accession_eq_row=None):
|
||||
if accession_eq_row is None:
|
||||
accession_eq_row = {}
|
||||
ws = wb.create_sheet("Přehled")
|
||||
ws.sheet_view.showGridLines = False
|
||||
|
||||
@@ -163,16 +194,24 @@ def write_prehled(wb, df):
|
||||
)
|
||||
|
||||
for r_idx, row in agg.iterrows():
|
||||
excel_row = r_idx + 3
|
||||
excel_row = r_idx + 3
|
||||
has_missing = row["not_received"] > 0
|
||||
fill = NOTRCV_FILL if has_missing else (EVEN_FILL if r_idx % 2 == 0 else ODD_FILL)
|
||||
accession = row["accession"]
|
||||
eq_row = accession_eq_row.get(accession) # None pokud nemá Open query
|
||||
|
||||
if eq_row:
|
||||
fill = OPEN_QUERY_FILL
|
||||
elif has_missing:
|
||||
fill = NOTRCV_FILL
|
||||
else:
|
||||
fill = EVEN_FILL if r_idx % 2 == 0 else ODD_FILL
|
||||
|
||||
col_date = row["collection_date"]
|
||||
date_str = col_date.strftime("%d-%b-%Y") if hasattr(col_date, "strftime") else str(col_date)
|
||||
|
||||
values = [
|
||||
row["investigator_no"], row["investigator_name"], row["patient_no"],
|
||||
row["protocol_visit_code"], row["accession"], date_str,
|
||||
row["protocol_visit_code"], accession, date_str,
|
||||
int(row["celkem"]), int(row["received"]), int(row["not_received"]),
|
||||
]
|
||||
for c_idx, val in enumerate(values, 1):
|
||||
@@ -180,7 +219,11 @@ def write_prehled(wb, df):
|
||||
cell.fill = fill
|
||||
cell.border = BORDER
|
||||
cell.alignment = CENTER if c_idx in (1, 4, 5, 6, 7, 8, 9) else LEFT
|
||||
if c_idx == 9 and has_missing:
|
||||
|
||||
if c_idx == 5 and eq_row:
|
||||
cell.hyperlink = f"#'eQueries'!A{eq_row}"
|
||||
cell.font = HYPERLINK_FONT
|
||||
elif c_idx == 9 and has_missing:
|
||||
cell.font = RED_FONT
|
||||
else:
|
||||
cell.font = NORMAL_FONT
|
||||
@@ -359,9 +402,66 @@ def write_kity(wb, df_kits):
|
||||
ws.freeze_panes = "A3"
|
||||
|
||||
|
||||
# ── sheet 4: ZDROJ (samples) ─────────────────────────────────────────────────
|
||||
# ── sheet 4: eQueries ────────────────────────────────────────────────────────
|
||||
|
||||
# ── sheet 5: ZDROJ Kity ──────────────────────────────────────────────────────
|
||||
def write_equeries(wb, df_eq):
|
||||
ws = wb.create_sheet("eQueries")
|
||||
ws.sheet_view.showGridLines = False
|
||||
|
||||
today = datetime.date.today().strftime("%d-%b-%Y")
|
||||
write_title(ws, f"eQueries — {STUDY} ({today})", 14)
|
||||
|
||||
headers = ["Site", "Investigátor", "Pacient", "Visit", "Accession",
|
||||
"Visit Datum", "eQuery ID", "Vytvořeno", "Odpovězeno",
|
||||
"Issue Type", "Status", "Čas odpovědi", "Uživatel", "Role"]
|
||||
widths = [9, 22, 14, 26, 13, 13, 10, 16, 16, 20, 9, 13, 22, 13]
|
||||
write_headers(ws, headers, widths)
|
||||
|
||||
def fmt_dt(val, fmt="%d-%b-%Y %H:%M"):
|
||||
if val is None or (isinstance(val, float) and val != val):
|
||||
return None
|
||||
try:
|
||||
if pd.isna(val):
|
||||
return None
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if hasattr(val, "strftime"):
|
||||
return val.strftime(fmt)
|
||||
return str(val)
|
||||
|
||||
for r_idx, row in df_eq.iterrows():
|
||||
excel_row = r_idx + 3
|
||||
is_open = str(row.get("status", "")).strip().lower() == "open"
|
||||
fill = OPEN_FILL if is_open else (EVEN_FILL if r_idx % 2 == 0 else ODD_FILL)
|
||||
font = Font(name="Arial", bold=True, size=10, color="9C0006") if is_open else NORMAL_FONT
|
||||
|
||||
values = [
|
||||
row["site_code"], row["investigator_name"], row["subject"],
|
||||
row["visit"], row["accession"],
|
||||
fmt_dt(row["visit_collection_date"], "%d-%b-%Y"),
|
||||
row["equery_id"],
|
||||
fmt_dt(row["create_date"]),
|
||||
fmt_dt(row["response_datetime"]),
|
||||
row["issue_type"], row["status"],
|
||||
row["time_before_response"], row["user_name"], row["study_role"],
|
||||
]
|
||||
for c_idx, val in enumerate(values, 1):
|
||||
if isinstance(val, float) and val != val:
|
||||
val = None
|
||||
cell = ws.cell(row=excel_row, column=c_idx, value=val)
|
||||
cell.fill = fill
|
||||
cell.border = BORDER
|
||||
cell.font = font
|
||||
cell.alignment = CENTER if c_idx in (1, 6, 7, 8, 9, 11, 12) else LEFT
|
||||
ws.row_dimensions[excel_row].height = 16
|
||||
|
||||
ws.freeze_panes = "A3"
|
||||
ws.auto_filter.ref = f"A2:N{len(df_eq) + 2}"
|
||||
|
||||
|
||||
# ── sheet 5: ZDROJ Vzorky ────────────────────────────────────────────────────
|
||||
|
||||
# ── sheet 6: ZDROJ Kity ──────────────────────────────────────────────────────
|
||||
|
||||
def write_zdroj_kity(wb, df_kits):
|
||||
ws = wb.create_sheet("ZDROJ Kity")
|
||||
@@ -427,6 +527,41 @@ def write_zdroj(wb, df):
|
||||
ws.auto_filter.ref = f"A1:{get_column_letter(len(headers))}1"
|
||||
|
||||
|
||||
def write_zdroj_equeries(wb, df_eq):
|
||||
ws = wb.create_sheet("ZDROJ eQuery")
|
||||
ws.sheet_view.showGridLines = True
|
||||
|
||||
headers = list(df_eq.columns)
|
||||
for c, h in enumerate(headers, 1):
|
||||
cell = ws.cell(row=1, column=c, value=h)
|
||||
cell.font = Font(name="Arial", bold=True, size=9, color="FFFFFF")
|
||||
cell.fill = PatternFill("solid", fgColor="404040")
|
||||
cell.alignment = LEFT
|
||||
cell.border = BORDER
|
||||
ws.column_dimensions[get_column_letter(c)].width = 20
|
||||
|
||||
for r_idx, (_, row) in enumerate(df_eq.iterrows(), 2):
|
||||
fill = EVEN_FILL if r_idx % 2 == 0 else ODD_FILL
|
||||
for c_idx, col in enumerate(headers, 1):
|
||||
val = row[col]
|
||||
try:
|
||||
is_na = pd.isna(val)
|
||||
except (TypeError, ValueError):
|
||||
is_na = False
|
||||
if is_na or val is None:
|
||||
val = ""
|
||||
elif hasattr(val, "strftime"):
|
||||
val = val.strftime("%Y-%m-%d %H:%M")
|
||||
cell = ws.cell(row=r_idx, column=c_idx, value=val)
|
||||
cell.font = Font(name="Arial", size=9)
|
||||
cell.fill = fill
|
||||
cell.border = BORDER
|
||||
cell.alignment = LEFT
|
||||
|
||||
ws.freeze_panes = "A2"
|
||||
ws.auto_filter.ref = f"A1:{get_column_letter(len(headers))}1"
|
||||
|
||||
|
||||
# ── main ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
@@ -435,20 +570,33 @@ def main():
|
||||
print("Načítám data z MySQL...")
|
||||
df = load_data()
|
||||
df_kits = load_kit_data()
|
||||
print(f" Vzorky: {len(df)} řádků, {df['patient_no'].nunique()} pacientů")
|
||||
print(f" Kity: {len(df_kits)} kitů, {df_kits['site_code'].nunique()} center")
|
||||
df_eq = load_equery_data()
|
||||
print(f" Vzorky: {len(df)} řádků, {df['patient_no'].nunique()} pacientů")
|
||||
print(f" Kity: {len(df_kits)} kitů, {df_kits['site_code'].nunique()} center")
|
||||
print(f" eQueries: {len(df_eq)} záznamů ({(df_eq['status']=='Open').sum()} Open)")
|
||||
|
||||
# mapping accession → řádek v listu eQueries (jen Open queries, první výskyt)
|
||||
open_accs = set(df_eq[df_eq["status"] == "Open"]["accession"].dropna())
|
||||
accession_eq_row = {}
|
||||
for r_idx, row in df_eq.iterrows():
|
||||
acc = row.get("accession")
|
||||
if acc and acc in open_accs and acc not in accession_eq_row:
|
||||
accession_eq_row[acc] = r_idx + 3 # řádek 1=title, 2=header, data od 3
|
||||
|
||||
wb = Workbook()
|
||||
wb.remove(wb.active)
|
||||
|
||||
write_prehled(wb, df)
|
||||
write_prehled(wb, df, accession_eq_row)
|
||||
write_chybejici(wb, df)
|
||||
write_kity(wb, df_kits)
|
||||
write_equeries(wb, df_eq)
|
||||
write_zdroj(wb, df)
|
||||
write_zdroj_kity(wb, df_kits)
|
||||
write_zdroj_equeries(wb, df_eq)
|
||||
|
||||
today = datetime.date.today().strftime("%Y-%m-%d")
|
||||
out_path = unique_path(f"{today} {STUDY} Covance Samples")
|
||||
now = datetime.datetime.now()
|
||||
stamp = now.strftime("%Y-%m-%d %H%M%S")
|
||||
out_path = unique_path(f"{stamp} {STUDY} Covance")
|
||||
wb.save(out_path)
|
||||
print(f"Uloženo: {out_path}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user