#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ sipiq_reminder_v1.1.py ====================== Verze: 1.1 Datum: 2026-06-18 Autor: Claude Code (pro MUDr. Vladimíra Buzalku) Změna proti v1.0 ---------------- - BEZ hlavičky From — do .eml se NEdává odesílací účet; JNJ Outlook doplní odesílatele z GAL a odešle přes JNJ Exchange (jediná možnost). Pravidlo 18JUN2026. v1.0 v TRASH. Popis ----- Vygeneruje .eml draft PŘIPOMÍNKY vyplnění SIPIQ (studie 77242113UCO3002 / DAWN) pro centra na KROK 6 (SIPIQ odeslán), která dlouho nereagovala. Vřelá prosba o vyplnění co nejdříve + odkaz na dotazník specifický pro centrum (sipiq.link z investigators) + bezpečnostní věta „pokud jste již vyplnil(a), ignorujte". To = email + email2 z investigators (+ EXTRA_TO ručně, dd-proxy vynechány), Cc = koordinátorky, from = vbuzalka@its.jnj.com, tělo BASE64 (Outlook čistě). Draft ≠ odesláno — STATUS „připomínka SIPIQ odeslána" psát až po ověření odeslání. Použití: python sipiq_reminder_v1.1.py --names "Matous,Kojecky,Jungwirthova,Krížová,Mudr" # dry-run python sipiq_reminder_v1.1.py --names "Matous,Kojecky,Jungwirthova,Krížová,Mudr" --apply Mongo 192.168.1.76:27017, bez auth, pymongo. """ import argparse import os import re import unicodedata from datetime import date from email.message import EmailMessage from pymongo import MongoClient OUT_DIR = r"u:\Dropbox\!!!Days\Downloads Z230\UploadToJNJ" CC = "AKocourk@ITS.JNJ.com, EBartoso@its.jnj.com" FROM = "vbuzalka@its.jnj.com" SIG = ("MUDr. Vladimír BUZALKA
" "ICON plc / Performing Local Trial Management Services for Janssen – Cilag s.r.o. " "/ Global Clinical Operations
" "Mobile: +420 775 735 276 / Fax: +420 227 012 284
" "E-mail: vbuzalka@its.jnj.com, vladimir.buzalka@iconplc.com") # Ručně doplněné adresy (z reply-checku / STATUS) — komu navíc poslat EXTRA_TO = { "Jungwirthova": ["a.jungwirthova@liberascientia.cz"], "Krížová": ["Viera.Krizova@fnmh.cz"], "Mudr": ["petr.pekny@nmskb.cz"], # dr. Pěkný komunikuje za dr. Mudra (dle STATUS) } CZ_MON = {1: "ledna", 2: "února", 3: "března", 4: "dubna", 5: "května", 6: "června", 7: "července", 8: "srpna", 9: "září", 10: "října", 11: "listopadu", 12: "prosince"} MON = {m: i + 1 for i, m in enumerate( ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"])} def ascii_slug(s): return "".join(c for c in unicodedata.normalize("NFKD", str(s or "")) if not unicodedata.combining(c)).lower().replace(" ", "") def sent_date_cz(status): dates = [] for ln in (status or "").splitlines(): if "SIPIQ odesl" in ln: m = re.match(r"(\d{2})([A-Za-z]{3})(\d{4})", ln.strip()) if m and m.group(2).upper() in MON: dates.append(date(int(m.group(3)), MON[m.group(2).upper()], int(m.group(1)))) if not dates: return None d = max(dates) return f"{d.day}. {CZ_MON[d.month]} {d.year}" def is_female(prijmeni): p = (prijmeni or "").lower() return p.endswith("ová") or p.endswith("ova") or p.endswith("á") def build_body(jmeno, prijmeni, sent_cz, link): f = is_female(prijmeni) greet = "Vážená paní doktorko," if f else "Vážený pane doktore," vyplnil = "vyplnila" if f else "vyplnil" sent_part = f" dne {sent_cz}" if sent_cz else "" return ( f'

{greet}

' f'

dovoluji si zdvořile připomenout feasibility dotazník SIPIQ ke studii ' f'77242113UCO3002 (DAWN) (přípravek icotrokinra, ulcerózní kolitida), ' f'který jsme Vám zaslali{sent_part}.

' f'

Velmi bychom ocenili jeho vyplnění co nejdříve — je pro nás klíčový pro ' f'posouzení Vašeho centra a další postup. Níže najdete odkaz na dotazník specifický ' f'pro Vaše centrum:

' f'

{link}

' f'

Pokud jste dotazník již {vyplnil}, přijměte prosím poděkování a tento e-mail ' f'ignorujte.

' f'

V případě jakýchkoli dotazů (např. potíže s odkazem) jsem Vám plně k dispozici. ' f'Předem děkuji za Váš čas a vstřícnost.

' f'

S pozdravem,
{SIG}

' ) def main(): ap = argparse.ArgumentParser() ap.add_argument("--names", required=True, help="příjmení čárkou (pi v investigators)") ap.add_argument("--apply", action="store_true") args = ap.parse_args() db = MongoClient("mongodb://192.168.1.76:27017", serverSelectionTimeoutMS=8000).feasibility names = [n.strip() for n in args.names.split(",") if n.strip()] docs = list(db.investigators.find({"prijmeni": {"$in": names}})) found = {d["prijmeni"] for d in docs} for n in names: if n not in found: print(f" ! nenalezeno: {n}") subject = "[Připomínka] 77242113UCO3002 (DAWN) — feasibility dotazník SIPIQ (prosba o vyplnění)" done = [] for d in docs: link = (d.get("sipiq") or {}).get("link") if not link: print(f" ! {d['prijmeni']}: chybí sipiq.link — přeskakuji"); continue tos = [e for e in [d.get("email"), d.get("email2")] if e] tos += EXTRA_TO.get(d["prijmeni"], []) tos = [e for e in dict.fromkeys(tos) if "dd-proxy" not in e.lower()] # dedup + bez proxy to = ", ".join(tos) sent_cz = sent_date_cz(d.get("STATUS")) body = build_body(d.get("jmeno"), d["prijmeni"], sent_cz, link) print(f" {d.get('jmeno')} {d['prijmeni']:14} | To: {to}") if not args.apply: continue msg = EmailMessage() # ŽÁDNÝ From — JNJ Outlook doplní odesílatele z GAL (odešle přes JNJ Exchange) msg["To"] = to msg["Cc"] = CC msg["Subject"] = subject msg["X-Unsent"] = "1" html = (f'' f'{body}') msg.set_content(html, subtype="html", charset="utf-8", cte="base64") os.makedirs(OUT_DIR, exist_ok=True) _t = date.today() _dd = _t.strftime("%d") + ["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"][_t.month-1] + _t.strftime("%Y") fn = f"pripominka_sipiq_{ascii_slug(d['prijmeni'])}_{_dd}.eml" with open(os.path.join(OUT_DIR, fn), "wb") as fh: fh.write(bytes(msg)) done.append(fn) if not args.apply: print(f"\n[DRY-RUN] {len(docs)} center, nic nezapsáno. Ostrý: --apply") else: print(f"\n[APPLY] Vygenerováno {len(done)} připomínek do {OUT_DIR}") if __name__ == "__main__": main()