z230
This commit is contained in:
+550
File diff suppressed because one or more lines are too long
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sipiq_report_v1.0.py
|
||||
====================
|
||||
Verze: 1.0
|
||||
Datum: 2026-06-17
|
||||
Autor: Claude Code (pro MUDr. Vladimíra Buzalku)
|
||||
|
||||
Popis
|
||||
-----
|
||||
Přehledný Excel report SIPIQ odpovědí: OTÁZKY ve sloupci A (v pořadí SIPIQ, seskupené
|
||||
dle sekcí), CENTRA ve sloupcích (B+). Buňka = odpověď daného centra na danou otázku.
|
||||
Tj. vyplněné SIPIQ všech center vedle sebe (= transponovaná rekonstrukce dotazníku).
|
||||
|
||||
Zdroj: MongoDB feasibility (sipiq_questions = slovník + pořadí + sekce + items;
|
||||
sipiq_responses = odpovědi + answers_supplement z doplnujici_dotazy).
|
||||
|
||||
Layout:
|
||||
- hlavička 2 řádky: příjmení PI + název centra (a země)
|
||||
- blok IDENTITA (země/město/PI/e-mail/sdl_site_id/datum vyplnění)
|
||||
- sekce SIPIQ jako barevné mezititulky, otázky a položky matic v řádcích
|
||||
- Yes = zelená, No = červená; doplněné odpovědi (answers_supplement) = oranžová + kurzíva + komentář
|
||||
- freeze panes (sloupec A + hlavička), ohraničení, vhodné šířky
|
||||
|
||||
Výstup: u:\\Dropbox\\!!!Days\\Downloads Z230\\SIPIQ_prehled_center_<ts>.xlsx
|
||||
Závislosti: pymongo, openpyxl (.venv). Mongo 192.168.1.76:27017, bez auth.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from pymongo import MongoClient
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.comments import Comment
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
MONGO_URI = "mongodb://192.168.1.76:27017"
|
||||
DB = "feasibility"
|
||||
OUT_DIR = r"u:\Dropbox\!!!Days\Downloads Z230"
|
||||
SKIP_SECTIONS = {"Confidentiality Statement"} # dlouhé právní souhlasy, ne data
|
||||
COUNTRY_ABBR = {"Czech Republic": "CZ", "Slovakia": "SK"}
|
||||
|
||||
# barvy
|
||||
C_SECTION = PatternFill("solid", fgColor="1F4E78") # tmavě modrá
|
||||
C_STEM = PatternFill("solid", fgColor="DDEBF7") # světle modrá
|
||||
C_IDENT = PatternFill("solid", fgColor="F2F2F2") # světle šedá
|
||||
C_HEAD = PatternFill("solid", fgColor="305496") # hlavička center
|
||||
C_YES = PatternFill("solid", fgColor="C6EFCE") # zelená
|
||||
C_NO = PatternFill("solid", fgColor="FFC7CE") # červená
|
||||
C_SUPP = PatternFill("solid", fgColor="FFE699") # oranžová (doplněno)
|
||||
THIN = Side(style="thin", color="BFBFBF")
|
||||
BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)
|
||||
WRAP_TOP = Alignment(wrap_text=True, vertical="top")
|
||||
WRAP_CTR = Alignment(wrap_text=True, vertical="center", horizontal="center")
|
||||
|
||||
|
||||
def fmt_date(s):
|
||||
if not s:
|
||||
return ""
|
||||
try:
|
||||
return datetime.strptime(str(s)[:10], "%Y-%m-%d").strftime("%d%b%Y").upper()
|
||||
except Exception:
|
||||
return str(s)[:10]
|
||||
|
||||
|
||||
def main():
|
||||
client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=8000)
|
||||
db = client[DB]
|
||||
client.admin.command("ping")
|
||||
|
||||
questions = list(db.sipiq_questions.find().sort("order", 1))
|
||||
resp = list(db.sipiq_responses.find())
|
||||
# seřadit centra: CZ -> SK, pak příjmení
|
||||
resp.sort(key=lambda r: (COUNTRY_ABBR.get(r.get("site_country"), "ZZ"),
|
||||
(r.get("pi_last_name") or "").lower()))
|
||||
n = len(resp)
|
||||
print(f"Otázek: {len(questions)} | center: {n}")
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "SIPIQ přehled"
|
||||
|
||||
# --- hlavička center (2 řádky) ---
|
||||
ws.cell(1, 1, "OTÁZKA \\ CENTRUM").font = Font(bold=True, color="FFFFFF")
|
||||
ws.cell(2, 1, "").font = Font(bold=True, color="FFFFFF")
|
||||
ws.merge_cells("A1:A2")
|
||||
for j, r in enumerate(resp):
|
||||
col = 2 + j
|
||||
c1 = ws.cell(1, col, r.get("pi_last_name") or "?")
|
||||
cc = COUNTRY_ABBR.get(r.get("site_country"), "?")
|
||||
c2 = ws.cell(2, col, f"{r.get('site_name') or ''} [{cc}]")
|
||||
for c in (c1, c2):
|
||||
c.font = Font(bold=True, color="FFFFFF", size=9)
|
||||
c.fill = C_HEAD
|
||||
c.alignment = WRAP_CTR
|
||||
c.border = BORDER
|
||||
ws.cell(1, 1).fill = C_HEAD
|
||||
ws.cell(1, 1).alignment = WRAP_CTR
|
||||
|
||||
row = 3
|
||||
|
||||
def ident_row(label, getter):
|
||||
nonlocal row
|
||||
a = ws.cell(row, 1, label)
|
||||
a.font = Font(bold=True)
|
||||
a.fill = C_IDENT
|
||||
a.alignment = WRAP_TOP
|
||||
a.border = BORDER
|
||||
for j, r in enumerate(resp):
|
||||
c = ws.cell(row, 2 + j, getter(r))
|
||||
c.fill = C_IDENT
|
||||
c.alignment = WRAP_TOP
|
||||
c.border = BORDER
|
||||
row += 1
|
||||
|
||||
# --- IDENTITA ---
|
||||
sec = ws.cell(row, 1, "■ IDENTITA CENTRA")
|
||||
sec.font = Font(bold=True, color="FFFFFF")
|
||||
sec.fill = C_SECTION
|
||||
for j in range(n):
|
||||
ws.cell(row, 2 + j).fill = C_SECTION
|
||||
row += 1
|
||||
ident_row("Země", lambda r: COUNTRY_ABBR.get(r.get("site_country"), r.get("site_country") or ""))
|
||||
ident_row("Město", lambda r: r.get("site_city") or "")
|
||||
ident_row("PI", lambda r: f"{r.get('pi_first_name') or ''} {r.get('pi_last_name') or ''}".strip())
|
||||
ident_row("E-mail PI", lambda r: r.get("pi_email") or "")
|
||||
ident_row("sdl_site_id", lambda r: r.get("sdl_site_id") or "")
|
||||
ident_row("Datum vyplnění", lambda r: fmt_date((r.get("meta") or {}).get("recorded_date")))
|
||||
|
||||
# --- OTÁZKY po sekcích ---
|
||||
cur_section = None
|
||||
for q in questions:
|
||||
section = q.get("section") or "Other"
|
||||
if section in SKIP_SECTIONS:
|
||||
continue
|
||||
if section != cur_section:
|
||||
cur_section = section
|
||||
sc = ws.cell(row, 1, f"■ {section.upper()}")
|
||||
sc.font = Font(bold=True, color="FFFFFF")
|
||||
sc.fill = C_SECTION
|
||||
sc.alignment = WRAP_TOP
|
||||
sc.border = BORDER
|
||||
for j in range(n):
|
||||
cc = ws.cell(row, 2 + j)
|
||||
cc.fill = C_SECTION
|
||||
cc.border = BORDER
|
||||
row += 1
|
||||
|
||||
base = q["_id"]
|
||||
items = q.get("items") or []
|
||||
if not items:
|
||||
_emit_answer_row(ws, row, f'{base} — {q.get("text") or ""}', base, resp, stem=False)
|
||||
row += 1
|
||||
else:
|
||||
# stem řádek (text otázky) — bez hodnot
|
||||
sc = ws.cell(row, 1, f'{base} — {q.get("text") or ""}')
|
||||
sc.font = Font(bold=True)
|
||||
sc.fill = C_STEM
|
||||
sc.alignment = WRAP_TOP
|
||||
sc.border = BORDER
|
||||
for j in range(n):
|
||||
cc = ws.cell(row, 2 + j)
|
||||
cc.fill = C_STEM
|
||||
cc.border = BORDER
|
||||
row += 1
|
||||
for it in items:
|
||||
lbl = it.get("label") or "(odpověď)"
|
||||
_emit_answer_row(ws, row, f" – {lbl}", it["key"], resp, stem=False)
|
||||
row += 1
|
||||
|
||||
# --- formátování ---
|
||||
ws.freeze_panes = "B3"
|
||||
ws.column_dimensions["A"].width = 58
|
||||
for j in range(n):
|
||||
ws.column_dimensions[get_column_letter(2 + j)].width = 20
|
||||
ws.row_dimensions[1].height = 28
|
||||
ws.row_dimensions[2].height = 40
|
||||
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
ts = datetime.now().strftime("%Y%m%d_%H%M")
|
||||
out = os.path.join(OUT_DIR, f"SIPIQ_prehled_center_{ts}.xlsx")
|
||||
wb.save(out)
|
||||
print(f"Uloženo: {out}")
|
||||
client.close()
|
||||
|
||||
|
||||
def _emit_answer_row(ws, row, label, key, resp, stem):
|
||||
a = ws.cell(row, 1, label)
|
||||
a.alignment = WRAP_TOP
|
||||
a.border = BORDER
|
||||
for j, r in enumerate(resp):
|
||||
ans = (r.get("answers") or {})
|
||||
supp = (r.get("answers_supplement") or {})
|
||||
c = ws.cell(row, 2 + j)
|
||||
c.alignment = WRAP_TOP
|
||||
c.border = BORDER
|
||||
if key in supp:
|
||||
val = (supp[key] or {}).get("value")
|
||||
c.value = val
|
||||
c.fill = C_SUPP
|
||||
c.font = Font(italic=True)
|
||||
src = (supp[key] or {}).get("answer_source") or "doplněno"
|
||||
c.comment = Comment(f"Doplněno mimo SIPIQ: {src}", "sipiq_report")
|
||||
else:
|
||||
val = ans.get(key)
|
||||
c.value = val
|
||||
if val == "Yes":
|
||||
c.fill = C_YES
|
||||
elif val == "No":
|
||||
c.fill = C_NO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,33 @@
|
||||
# sipiq_report_v1.1 — přehledný Excel report SIPIQ (centra × otázky)
|
||||
|
||||
**Verze:** 1.1 · **Datum:** 2026-06-17 · **Studie:** 77242113UCO3002 (ICONIC / DAWN)
|
||||
|
||||
## Co dělá
|
||||
Excel report: **otázky ve sloupci A** (v pořadí SIPIQ, seskupené dle sekcí), **centra ve sloupcích**
|
||||
(B+). Buňka = odpověď centra na otázku → vyplněné SIPIQ všech center vedle sebe.
|
||||
Čte z MongoDB `feasibility`: `sipiq_questions` (slovník+pořadí+sekce+items) + `sipiq_responses`
|
||||
(answers + `answers_supplement`).
|
||||
|
||||
## Layout
|
||||
- Hlavička 2 řádky: **příjmení PI** + **název centra [země]**; centra seřazena CZ→SK, pak příjmení.
|
||||
- Blok **IDENTITA** (země/město/PI/e-mail/sdl_site_id/datum vyplnění).
|
||||
- Sekce SIPIQ jako barevné mezititulky; jednotlivé otázky a položky matic v řádcích.
|
||||
- **Yes=zelená, No=červená**; doplněné odpovědi (`answers_supplement`) = oranžová + kurzíva + komentář se zdrojem.
|
||||
- **Freeze panes B3** (sloupec A + hlavička), ohraničení, šířky (A=58, centra=20).
|
||||
|
||||
## Změny proti v1.0
|
||||
- **Contact Information SBALENA** do 5 řádků (má koordinátora? / koordinátor jméno+e-mail /
|
||||
CDA vyjednává / dotazník vyplnil) místo ~44; PI je už v IDENTITA. → `COMPACT_CONTACT`.
|
||||
- **Q54** (doporučení dalších center) = JEDEN zřetězený řádek místo rozbitých „PI Name: - No Name" řádků.
|
||||
- Confidentiality Statement (Q14–Q21, právní souhlasy) se vynechává (`SKIP_SECTIONS`).
|
||||
- Řádků: 179 → 126.
|
||||
|
||||
## Použití
|
||||
```
|
||||
.venv\Scripts\python.exe Feasibility\sipiq_report_v1.1.py
|
||||
```
|
||||
Výstup: `u:\Dropbox\!!!Days\Downloads Z230\SIPIQ_prehled_center_<ts>.xlsx`.
|
||||
Bez argumentů — vždy aktuální stav DB (vč. doplněných odpovědí). pymongo + openpyxl.
|
||||
|
||||
## Stav 17JUN2026
|
||||
56 otázek × 15 center, 126 řádků. v1.0 v `Feasibility\TRASH`.
|
||||
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sipiq_report_v1.1.py
|
||||
====================
|
||||
Verze: 1.1
|
||||
Datum: 2026-06-17
|
||||
Autor: Claude Code (pro MUDr. Vladimíra Buzalku)
|
||||
|
||||
Změny proti v1.0
|
||||
----------------
|
||||
- Contact Information SBALENA do kompaktního bloku (koordinátor jméno+e-mail, má koordinátora?,
|
||||
kdo vyjednává CDA, kdo vyplnil dotazník) místo ~44 řádků; PI je už v bloku IDENTITA.
|
||||
- Q54 (doporučení dalších center) sloučeno do JEDNOHO řádku (zřetězené neprázdné hodnoty)
|
||||
místo rozbitých „PI Name: - No Name - -" řádků. Stará v1.0 v TRASH.
|
||||
|
||||
Popis
|
||||
-----
|
||||
Přehledný Excel report SIPIQ: OTÁZKY ve sloupci A (pořadí + sekce), CENTRA ve sloupcích (B+).
|
||||
Zdroj MongoDB feasibility (sipiq_questions + sipiq_responses + answers_supplement).
|
||||
Yes=zelená, No=červená; doplněné odpovědi oranžová+kurzíva+komentář; freeze panes B3.
|
||||
|
||||
Výstup: u:\\Dropbox\\!!!Days\\Downloads Z230\\SIPIQ_prehled_center_<ts>.xlsx
|
||||
Závislosti: pymongo, openpyxl (.venv). Mongo 192.168.1.76:27017, bez auth.
|
||||
"""
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from pymongo import MongoClient
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.comments import Comment
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
MONGO_URI = "mongodb://192.168.1.76:27017"
|
||||
DB = "feasibility"
|
||||
OUT_DIR = r"u:\Dropbox\!!!Days\Downloads Z230"
|
||||
SKIP_SECTIONS = {"Confidentiality Statement"}
|
||||
COUNTRY_ABBR = {"Czech Republic": "CZ", "Slovakia": "SK"}
|
||||
|
||||
# kompaktní Contact Information: (label, [answer keys], spojovník)
|
||||
COMPACT_CONTACT = [
|
||||
("Má centrum koordinátora?", ["Q7"], ""),
|
||||
("Koordinátor (jméno)", ["Q8_2", "Q8_1"], " "),
|
||||
("Koordinátor (e-mail)", ["Q8_8"], ""),
|
||||
("CDA vyjednává", ["Q10"], ""),
|
||||
("Dotazník vyplnil", ["Q12"], ""),
|
||||
]
|
||||
|
||||
C_SECTION = PatternFill("solid", fgColor="1F4E78")
|
||||
C_STEM = PatternFill("solid", fgColor="DDEBF7")
|
||||
C_IDENT = PatternFill("solid", fgColor="F2F2F2")
|
||||
C_HEAD = PatternFill("solid", fgColor="305496")
|
||||
C_YES = PatternFill("solid", fgColor="C6EFCE")
|
||||
C_NO = PatternFill("solid", fgColor="FFC7CE")
|
||||
C_SUPP = PatternFill("solid", fgColor="FFE699")
|
||||
THIN = Side(style="thin", color="BFBFBF")
|
||||
BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)
|
||||
WRAP_TOP = Alignment(wrap_text=True, vertical="top")
|
||||
WRAP_CTR = Alignment(wrap_text=True, vertical="center", horizontal="center")
|
||||
|
||||
|
||||
def fmt_date(s):
|
||||
if not s:
|
||||
return ""
|
||||
try:
|
||||
return datetime.strptime(str(s)[:10], "%Y-%m-%d").strftime("%d%b%Y").upper()
|
||||
except Exception:
|
||||
return str(s)[:10]
|
||||
|
||||
|
||||
def main():
|
||||
client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=8000)
|
||||
db = client[DB]
|
||||
client.admin.command("ping")
|
||||
|
||||
questions = list(db.sipiq_questions.find().sort("order", 1))
|
||||
resp = list(db.sipiq_responses.find())
|
||||
resp.sort(key=lambda r: (COUNTRY_ABBR.get(r.get("site_country"), "ZZ"),
|
||||
(r.get("pi_last_name") or "").lower()))
|
||||
n = len(resp)
|
||||
print(f"Otázek: {len(questions)} | center: {n}")
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "SIPIQ přehled"
|
||||
state = {"row": 1}
|
||||
|
||||
# --- hlavička center ---
|
||||
h = ws.cell(1, 1, "OTÁZKA \\ CENTRUM")
|
||||
h.font = Font(bold=True, color="FFFFFF"); h.fill = C_HEAD; h.alignment = WRAP_CTR
|
||||
ws.cell(2, 1, "")
|
||||
ws.merge_cells("A1:A2")
|
||||
for j, r in enumerate(resp):
|
||||
cc = COUNTRY_ABBR.get(r.get("site_country"), "?")
|
||||
for rr, val in ((1, r.get("pi_last_name") or "?"), (2, f"{r.get('site_name') or ''} [{cc}]")):
|
||||
c = ws.cell(rr, 2 + j, val)
|
||||
c.font = Font(bold=True, color="FFFFFF", size=9); c.fill = C_HEAD
|
||||
c.alignment = WRAP_CTR; c.border = BORDER
|
||||
state["row"] = 3
|
||||
|
||||
def section_header(title):
|
||||
row = state["row"]
|
||||
sc = ws.cell(row, 1, f"■ {title.upper()}")
|
||||
sc.font = Font(bold=True, color="FFFFFF"); sc.fill = C_SECTION
|
||||
sc.alignment = WRAP_TOP; sc.border = BORDER
|
||||
for j in range(n):
|
||||
c = ws.cell(row, 2 + j); c.fill = C_SECTION; c.border = BORDER
|
||||
state["row"] += 1
|
||||
|
||||
def combo_row(label, keys, sep, fill=None):
|
||||
row = state["row"]
|
||||
a = ws.cell(row, 1, label)
|
||||
a.alignment = WRAP_TOP; a.border = BORDER
|
||||
if fill:
|
||||
a.fill = fill; a.font = Font(bold=True)
|
||||
for j, r in enumerate(resp):
|
||||
ans = r.get("answers") or {}
|
||||
supp = r.get("answers_supplement") or {}
|
||||
c = ws.cell(row, 2 + j); c.alignment = WRAP_TOP; c.border = BORDER
|
||||
if fill:
|
||||
c.fill = fill
|
||||
vals, supp_hit, supp_src = [], False, None
|
||||
for k in keys:
|
||||
if k in supp:
|
||||
vals.append((supp[k] or {}).get("value")); supp_hit = True
|
||||
supp_src = (supp[k] or {}).get("answer_source") or "doplněno"
|
||||
elif ans.get(k):
|
||||
vals.append(ans.get(k))
|
||||
val = sep.join(x for x in vals if x)
|
||||
c.value = val or None
|
||||
if supp_hit:
|
||||
c.fill = C_SUPP; c.font = Font(italic=True)
|
||||
c.comment = Comment(f"Doplněno mimo SIPIQ: {supp_src}", "sipiq_report")
|
||||
elif val == "Yes":
|
||||
c.fill = C_YES
|
||||
elif val == "No":
|
||||
c.fill = C_NO
|
||||
state["row"] += 1
|
||||
|
||||
# --- IDENTITA ---
|
||||
section_header("Identita centra")
|
||||
for label, getter in [
|
||||
("Země", lambda r: COUNTRY_ABBR.get(r.get("site_country"), r.get("site_country") or "")),
|
||||
("Město", lambda r: r.get("site_city") or ""),
|
||||
("PI", lambda r: f"{r.get('pi_first_name') or ''} {r.get('pi_last_name') or ''}".strip()),
|
||||
("E-mail PI", lambda r: r.get("pi_email") or ""),
|
||||
("sdl_site_id", lambda r: r.get("sdl_site_id") or ""),
|
||||
("Datum vyplnění", lambda r: fmt_date((r.get("meta") or {}).get("recorded_date"))),
|
||||
]:
|
||||
row = state["row"]
|
||||
a = ws.cell(row, 1, label); a.font = Font(bold=True); a.fill = C_IDENT
|
||||
a.alignment = WRAP_TOP; a.border = BORDER
|
||||
for j, r in enumerate(resp):
|
||||
c = ws.cell(row, 2 + j, getter(r)); c.fill = C_IDENT
|
||||
c.alignment = WRAP_TOP; c.border = BORDER
|
||||
state["row"] += 1
|
||||
|
||||
# --- OTÁZKY po sekcích ---
|
||||
cur_section = None
|
||||
contact_done = False
|
||||
for q in questions:
|
||||
section = q.get("section") or "Other"
|
||||
if section in SKIP_SECTIONS:
|
||||
continue
|
||||
|
||||
if section == "Contact Information":
|
||||
if contact_done:
|
||||
continue
|
||||
section_header("Kontakty (koordinátor / CDA / vyplnil)")
|
||||
for label, keys, sep in COMPACT_CONTACT:
|
||||
combo_row(label, keys, sep)
|
||||
contact_done = True
|
||||
cur_section = section
|
||||
continue
|
||||
|
||||
if section != cur_section:
|
||||
section_header(section)
|
||||
cur_section = section
|
||||
|
||||
base = q["_id"]
|
||||
# Q54 = doporučení dalších center -> jeden zřetězený řádek
|
||||
if base == "Q54":
|
||||
keys = [it["key"] for it in (q.get("items") or [])] or [base]
|
||||
combo_row("Q54 — Doporučená další centra/investigátoři", keys, "; ")
|
||||
continue
|
||||
|
||||
items = q.get("items") or []
|
||||
if not items:
|
||||
combo_row(f'{base} — {q.get("text") or ""}', [base], "")
|
||||
else:
|
||||
row = state["row"]
|
||||
sc = ws.cell(row, 1, f'{base} — {q.get("text") or ""}')
|
||||
sc.font = Font(bold=True); sc.fill = C_STEM
|
||||
sc.alignment = WRAP_TOP; sc.border = BORDER
|
||||
for j in range(n):
|
||||
c = ws.cell(row, 2 + j); c.fill = C_STEM; c.border = BORDER
|
||||
state["row"] += 1
|
||||
for it in items:
|
||||
lbl = it.get("label") or "(odpověď)"
|
||||
combo_row(f" – {lbl}", [it["key"]], "")
|
||||
|
||||
# --- formátování ---
|
||||
ws.freeze_panes = "B3"
|
||||
ws.column_dimensions["A"].width = 58
|
||||
for j in range(n):
|
||||
ws.column_dimensions[get_column_letter(2 + j)].width = 20
|
||||
ws.row_dimensions[1].height = 28
|
||||
ws.row_dimensions[2].height = 40
|
||||
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
ts = datetime.now().strftime("%Y%m%d_%H%M")
|
||||
out = os.path.join(OUT_DIR, f"SIPIQ_prehled_center_{ts}.xlsx")
|
||||
wb.save(out)
|
||||
print(f"Uloženo: {out}")
|
||||
client.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user