Pridani novych skriptu, reportu a zpracovanych dat
- EmailsImport: jnj_mailbox_sync_v1.0 (sync JNJ schranky) - Covance: create_lab_results_report_v1.0 + zpracovane CSV (samples/kits/equeries/test-results), browser profily - Feasibility UCO2001: store_cda_*, store_sipiq_links, classify_krok, mark_sipiq_sent, report v1.1 (stary report do TRASH) - IWRS/Drugs: pregenerovane onsite inventory / shipment reporty - TrilliumMCP server + trilium upload/diacritics skripty - .mcp.json Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# classify_krok_v1.0.py
|
||||
|
||||
**Verze:** 1.0 · **Datum:** 2026-06-09
|
||||
|
||||
Odvozuje pole **`KROK`** (krok feasibility workflow) ze `STATUS` u každého
|
||||
investigatora v Mongo `feasibility.investigators` a zapíše jej. Znovu-spustitelné.
|
||||
|
||||
## Kroky workflow (DAWN / 77242113UCO3002)
|
||||
| KROK | Význam |
|
||||
|------|--------|
|
||||
| `0 - mimo (nedoruceno/neplatny kontakt)` | bounce, špatný kontakt |
|
||||
| `0 - nechceme (nase rozhodnuti)` | naše rozhodnutí na začátku, centrum se NEoslovovalo (STATUS „Nechceme"/„Rejected"). POZOR: ≠ „Nezájem" (to je odpověď lékaře = 3.2) |
|
||||
| `1 - nabidka odeslana` | odesláno, bez připomínky/odpovědi |
|
||||
| `2 - nabidka pripomenuta` | 1. připomínka odeslaná, bez odpovědi |
|
||||
| `3.1 - odpovedel: ma zajem` | zájem, CDA zatím nevyžádáno |
|
||||
| `3.2 - odpovedel: nema zajem` | nezájem / Nechceme / Rejected |
|
||||
| `4 - zajem, CDA vyzadano` | CDA u CTA, nepodepsáno (root „vyžád" + cda / „čekáme na cda") |
|
||||
| `5 - CDA podepsano` | fully signed / máme CDA / podepsáno |
|
||||
| `6 - SIPIQ odeslan` | (zatím 0) |
|
||||
| `7 - SIPIQ vyplneny` | (zatím 0) |
|
||||
|
||||
## Logika
|
||||
- Priorita pravidel (shora): 0 → 7 → 6 → 5 → 4 → 3.2 → 3.1 → 2 → 1.
|
||||
- KROK = nejvyšší dosažený stav. „Nutno poslat SIPIQ" = krok 5 (CDA máme, SIPIQ ještě neodeslán).
|
||||
- `OVERRIDES` (STATUS bez jednoznačného klíč. slova):
|
||||
- Dzuriková → 3.1 (odpověděla, chce telefonát k domluvě o účasti; slovo „zájem" chybí)
|
||||
- Reif → 1 (právě odeslána 1. oficiální nabídka; čeká se na přímou odpověď)
|
||||
- Košková → 3.2 (decline: „nemá kapacitu, nezapojí se")
|
||||
- `EXPECTED` = kontrolní počty (09JUN2026, po odeslání SIPIQ): 0-mimo:4, 0-nechceme:36, 1:25, 2:25, 3.1:3, 3.2:12, 4:11, 5:0, 6:14, 7:0.
|
||||
- **Rozdíl Nechceme vs Nezájem:** „Nechceme"/„Rejected" = naše rozhodnutí (krok 0,
|
||||
bez oslovení); „Nezájem"/„NEMÁ zájem" = lékař odpověděl záporně (krok 3.2).
|
||||
|
||||
## Spuštění
|
||||
```
|
||||
python classify_krok_v1.0.py # dry-run (výpis + kontrola počtů)
|
||||
python classify_krok_v1.0.py --apply # zápis KROK do Mongo
|
||||
```
|
||||
venv: `U:\PythonProject\Janssen\.venv\Scripts\python.exe`
|
||||
|
||||
## Historie
|
||||
- v1.0 — první verze; aplikováno 09JUN2026 na 130 záznamů.
|
||||
@@ -0,0 +1,143 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: classify_krok_v1.0.py
|
||||
# Verze: 1.0
|
||||
# Datum: 2026-06-09
|
||||
# Popis: Odvodi pole KROK (krok feasibility workflow) ze STATUS u kazdeho
|
||||
# investigatora v Mongo feasibility.investigators a zapise jej.
|
||||
# Workflow kroky (DAWN / 77242113UCO3002):
|
||||
# 1 - nabidka odeslana
|
||||
# 2 - nabidka pripomenuta
|
||||
# 3.1 - odpovedel: ma zajem (CDA jeste nevyzadano)
|
||||
# 3.2 - odpovedel: nema zajem (nezajem / Nechceme / Rejected)
|
||||
# 4 - zajem, CDA vyzadano (u CTA, nepodepsano)
|
||||
# 5 - CDA podepsano (fully signed / mame CDA / master)
|
||||
# 6 - SIPIQ odeslan
|
||||
# 7 - SIPIQ vyplneny
|
||||
# 0 - mimo (nedoruceno / neplatny kontakt)
|
||||
# KROK se odvozuje ze STATUS (znovu-spustitelne). Pro pripady, kde
|
||||
# STATUS neobsahuje klicove slovo, jsou explicitni OVERRIDES.
|
||||
# Pouziti: python classify_krok_v1.0.py (dry-run, jen vypis)
|
||||
# python classify_krok_v1.0.py --apply (zapise KROK do Mongo)
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pymongo import MongoClient
|
||||
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://192.168.1.76:27017")
|
||||
|
||||
# --- Stitky kroku ---
|
||||
K0 = "0 - mimo (nedoruceno/neplatny kontakt)"
|
||||
K0N = "0 - nechceme (nase rozhodnuti)"
|
||||
K1 = "1 - nabidka odeslana"
|
||||
K2 = "2 - nabidka pripomenuta"
|
||||
K31 = "3.1 - odpovedel: ma zajem"
|
||||
K32 = "3.2 - odpovedel: nema zajem"
|
||||
K4 = "4 - zajem, CDA vyzadano"
|
||||
K5 = "5 - CDA podepsano"
|
||||
K6 = "6 - SIPIQ odeslan"
|
||||
K7 = "7 - SIPIQ vyplneny"
|
||||
|
||||
# Explicitni vyjimky (STATUS neobsahuje jednoznacne klicove slovo)
|
||||
# - Dzurikova: odpovedela, chce telefonat k domluve o ucasti (zajem), ale slovo
|
||||
# "zajem" v STATUS neni -> 3.1
|
||||
# - Reif: prave odeslana 1. oficialni nabidka, ackoliv zajem projevil pres
|
||||
# EFERTUS -> ponechat v kroku 1 (cekame na primou odpoved)
|
||||
OVERRIDES = {
|
||||
"6a19832b5fc2213518257964": K31, # Dzurikova Michaela
|
||||
"6a268cdeb84bf5597759b478": K1, # Reif Stanislav
|
||||
"6a19832b5fc2213518257979": K32, # Koskova Radka (nema kapacitu, nezapoji se)
|
||||
}
|
||||
|
||||
# Ocekavane pocty (dle odsouhlasene klasifikace 09JUN2026) pro kontrolu
|
||||
EXPECTED = {K0: 4, K0N: 36, K1: 25, K2: 25, K31: 3, K32: 12, K4: 11, K5: 0, K6: 14, K7: 0}
|
||||
|
||||
|
||||
def classify(status: str) -> str:
|
||||
s = (status or "").lower()
|
||||
|
||||
# 0 - nedorucitelne / spatny kontakt
|
||||
if "nedorucen" in s or "neplatna adresa" in s or "neplatná adresa" in s or "spatny kontakt" in s or "špatný kontakt" in s:
|
||||
return K0
|
||||
# 0 - NECHCEME = nase rozhodnuti na zacatku (centrum se neoslovovalo, zadny dalsi krok).
|
||||
# Odlisit od "nezajem" (odpoved lekare = 3.2).
|
||||
if "nechceme" in s or "rejected" in s:
|
||||
return K0N
|
||||
# 7 - SIPIQ vyplneny
|
||||
if "sipiq" in s and ("vyplnen" in s or "vyplněn" in s):
|
||||
return K7
|
||||
# 6 - SIPIQ odeslan (pozor: "nutno poslat/odeslat SIPIQ" NENI odeslano)
|
||||
if "sipiq odeslan" in s or "sipiq odeslán" in s or "odeslan sipiq" in s or "odeslán sipiq" in s:
|
||||
return K6
|
||||
# 5 - CDA podepsano (mame CDA / fully signed / podepsano)
|
||||
if "fully signed" in s or "mame cda" in s or "máme cda" in s or "cda podeps" in s or "podepsano" in s or "podepsáno" in s:
|
||||
return K5
|
||||
# 4 - zajem, CDA vyzadano / cekame na CDA
|
||||
# (CDA jeste nepodepsano - krok 5 se kontroluje vyse). Detekce pres koren "vyzad".
|
||||
if ("cda" in s and ("vyžád" in s or "vyzad" in s)) or "čekáme na cda" in s or "cekame na cda" in s:
|
||||
return K4
|
||||
# 3.2 - nema zajem
|
||||
if "nezájem" in s or "nezajem" in s or "nechceme" in s or "rejected" in s or "nemá zájem" in s or "nema zajem" in s:
|
||||
return K32
|
||||
# 3.1 - ma zajem
|
||||
if "zájem" in s or "zajem" in s:
|
||||
return K31
|
||||
# 2 - pripomenuta
|
||||
if "připomínka odeslan" in s or "pripominka odeslan" in s:
|
||||
return K2
|
||||
# 1 - nabidka odeslana (default)
|
||||
return K1
|
||||
|
||||
|
||||
def main():
|
||||
apply = "--apply" in sys.argv
|
||||
client = MongoClient(MONGO_URI)
|
||||
col = client["feasibility"]["investigators"]
|
||||
docs = list(col.find({}, {"prijmeni": 1, "jmeno": 1, "STATUS": 1}))
|
||||
print(f"Nacteno {len(docs)} zaznamu.\n")
|
||||
|
||||
counts = {}
|
||||
rows = []
|
||||
for d in docs:
|
||||
_id = str(d["_id"])
|
||||
krok = OVERRIDES.get(_id) or classify(d.get("STATUS", ""))
|
||||
counts[krok] = counts.get(krok, 0) + 1
|
||||
rows.append((krok, d.get("prijmeni", ""), d.get("jmeno", ""), _id))
|
||||
|
||||
# Vypis po krocich
|
||||
rows.sort(key=lambda r: r[0])
|
||||
for krok in sorted(set(r[0] for r in rows)):
|
||||
members = [f"{r[1]} {r[2]}".strip() for r in rows if r[0] == krok]
|
||||
print(f"[{krok}] ({len(members)})")
|
||||
print(" " + ", ".join(members))
|
||||
print()
|
||||
|
||||
# Kontrola proti ocekavani
|
||||
print("--- Kontrola poctu (ocekavano vs. spocteno) ---")
|
||||
ok = True
|
||||
for k in [K0, K0N, K1, K2, K31, K32, K4, K5, K6, K7]:
|
||||
exp = EXPECTED.get(k, 0)
|
||||
got = counts.get(k, 0)
|
||||
flag = "OK" if exp == got else "!!! MISMATCH"
|
||||
if exp != got:
|
||||
ok = False
|
||||
print(f" {k:45s} exp={exp:3d} got={got:3d} {flag}")
|
||||
print("Souhrn:", "VSE SEDI" if ok else "NESEDI - zkontroluj pravidla/OVERRIDES")
|
||||
print()
|
||||
|
||||
if not apply:
|
||||
print(">>> DRY-RUN. Pro zapis spust s --apply")
|
||||
return
|
||||
|
||||
# Zapis
|
||||
n = 0
|
||||
for krok, _, _, _id_str in rows:
|
||||
from bson import ObjectId
|
||||
res = col.update_one({"_id": ObjectId(_id_str)}, {"$set": {"KROK": krok}})
|
||||
n += res.modified_count
|
||||
print(f">>> ZAPSANO: KROK aktualizovan u {n} zaznamu (z {len(rows)}).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,69 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: mark_sipiq_sent_v1.0.py
|
||||
# Verze: 1.0
|
||||
# Datum: 2026-06-09
|
||||
# Popis: Predřadi do STATUS radek "09JUN2026: SIPIQ odeslán" u 14 investigatoru
|
||||
# (krok 5 -> po odeslani SIPIQ). Idempotentni (nepridava 2x stejny den).
|
||||
# Po zapisu spustit classify_krok_v1.0.py --apply (prejdou na KROK 6).
|
||||
# Pouziti: python mark_sipiq_sent_v1.0.py (dry-run)
|
||||
# python mark_sipiq_sent_v1.0.py --apply (zapise)
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pymongo import MongoClient
|
||||
from bson import ObjectId
|
||||
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://192.168.1.76:27017")
|
||||
LINE = "09JUN2026: SIPIQ odeslán"
|
||||
|
||||
IDS = [
|
||||
("6a1c4275aa46d8b608065cec", "Lukac"),
|
||||
("6a19832b5fc221351825794f", "Hlavaty"),
|
||||
("6a19832b5fc2213518257954", "Fedurco"),
|
||||
("6a198b661218c31ab0f5ba43", "Tichy"),
|
||||
("6a19832b5fc221351825796e", "Falc"),
|
||||
("6a198b661218c31ab0f5ba41", "Pesta"),
|
||||
("6a198b661218c31ab0f5ba45", "Jungwirthova"),
|
||||
("6a19832b5fc2213518257950", "Matous"),
|
||||
("6a19832b5fc2213518257958", "Mihalkanin"),
|
||||
("6a198b661218c31ab0f5ba4e", "Krizova"),
|
||||
("6a19832b5fc221351825795e", "Stepek"),
|
||||
("6a19832b5fc2213518257972", "Konecny"),
|
||||
("6a1987481218c31ab0f5ba33", "Svoboda"),
|
||||
("6a198b661218c31ab0f5ba42", "Kojecky"),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
apply = "--apply" in sys.argv
|
||||
client = MongoClient(MONGO_URI)
|
||||
col = client["feasibility"]["investigators"]
|
||||
|
||||
print("=== NAHLED: predazeni STATUS radku ===\n")
|
||||
n = 0
|
||||
for inv_id, label in IDS:
|
||||
doc = col.find_one({"_id": ObjectId(inv_id)}, {"STATUS": 1})
|
||||
if not doc:
|
||||
print(f"!!! NENALEZEN {label} ({inv_id})")
|
||||
continue
|
||||
status = doc.get("STATUS", "") or ""
|
||||
if LINE in status:
|
||||
print(f"[SKIP] {label}: radek uz existuje")
|
||||
continue
|
||||
new_status = LINE + "\n" + status
|
||||
print(f"[OK] {label}: + '{LINE}'")
|
||||
if apply:
|
||||
res = col.update_one({"_id": ObjectId(inv_id)}, {"$set": {"STATUS": new_status}})
|
||||
n += res.modified_count
|
||||
|
||||
print()
|
||||
if apply:
|
||||
print(f">>> ZAPSANO: {n} zaznamu. Ted spust classify_krok_v1.0.py --apply")
|
||||
else:
|
||||
print(">>> DRY-RUN. Pro zapis spust s --apply")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,26 @@
|
||||
# report_77242113UCO2001_v1.1.py
|
||||
|
||||
**Verze:** 1.1 · **Datum:** 2026-06-09
|
||||
|
||||
Generátor Excel reportu z Mongo `feasibility.investigators`.
|
||||
|
||||
## Změny v1.1
|
||||
- Přidán sloupec **`KROK`** (krok feasibility workflow) **hned PŘED `STATUS`**.
|
||||
- Barevné odlišení řádků dle KROK (místo dle STATUS):
|
||||
- 5/6/7 zelená, 4 tmavší zelená, 3.1 světle modrá, 3.2 červená,
|
||||
2 světle žlutá, 1 modrá, 0 šedá. KROK tučně.
|
||||
- KROK plní skript `classify_krok_v1.0.py` (odvození ze STATUS).
|
||||
|
||||
## Pořadí sloupců
|
||||
`Příjmení | Jméno | Email | KROK | STATUS | Kritická poznámka | Země | Pracoviště | Internet summary | …`
|
||||
|
||||
## Spuštění / výstup
|
||||
```
|
||||
python report_77242113UCO2001_v1.1.py
|
||||
```
|
||||
- venv: `U:\PythonProject\Janssen\.venv\Scripts\python.exe`
|
||||
- výstup: `u:\Dropbox\!!!Days\Downloads Z230\77242113UCO2001_investigators_<YYYYMMDD_HHMM>.xlsx`
|
||||
|
||||
## Historie
|
||||
- v1.0 (bez verze v názvu) — původní, přesunuto do `TRASH/`.
|
||||
- v1.1 — sloupec KROK před STATUS + obarvení dle KROK.
|
||||
@@ -0,0 +1,157 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: report_77242113UCO2001_v1.1.py
|
||||
# Verze: 1.1
|
||||
# Datum: 2026-06-09
|
||||
# Popis: Generator Excel reportu z Mongo feasibility.investigators.
|
||||
# v1.1 - pridan sloupec KROK (krok feasibility workflow) HNED PRED
|
||||
# STATUS + barevne odliseni dle KROK. KROK plni skript
|
||||
# classify_krok_v1.0.py (odvozeni ze STATUS).
|
||||
# Projekt: 77242113UCO2001 (DAWN / spravny kod 77242113UCO3002)
|
||||
# Vystup: u:\Dropbox\!!!Days\Downloads Z230\ (verzovany nazev s timestampem)
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pymongo import MongoClient
|
||||
import openpyxl
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
# --- Připojení k MongoDB ---
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://192.168.1.76:27017")
|
||||
client = MongoClient(MONGO_URI)
|
||||
db = client["feasibility"]
|
||||
col = db["investigators"]
|
||||
|
||||
# --- Načtení dat ---
|
||||
docs = list(col.find({}))
|
||||
print(f"Načteno {len(docs)} záznamů.")
|
||||
|
||||
# --- Cílová složka ---
|
||||
OUTPUT_DIR = r"u:\Dropbox\!!!Days\Downloads Z230"
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
datum = datetime.now().strftime("%Y%m%d_%H%M")
|
||||
filename = f"77242113UCO2001_investigators_{datum}.xlsx"
|
||||
filepath = os.path.join(OUTPUT_DIR, filename)
|
||||
|
||||
# --- Definice sloupců ---
|
||||
# Pořadí: jméno, email, KROK, STATUS, kriticka_poznamka, pak ostatní
|
||||
# KROK je ZÁMĚRNĚ hned PŘED STATUS.
|
||||
FIXED_COLS = [
|
||||
("prijmeni", "Příjmení"),
|
||||
("jmeno", "Jméno"),
|
||||
("email", "Email"),
|
||||
("KROK", "KROK"),
|
||||
("STATUS", "STATUS"),
|
||||
("kriticka_poznamka", "Kritická poznámka"),
|
||||
("zeme", "Země"),
|
||||
("pracoviste", "Pracoviště"),
|
||||
("internet_summary","Internet summary"),
|
||||
]
|
||||
|
||||
# Klíče, které přeskočíme (složité nested objekty)
|
||||
SKIP_KEYS = {"_id", "excel", "sites_illuminator", "maf", "zdroje", "studie", "Viper_Performance", "Viper_Contacts"}
|
||||
|
||||
# Ostatní skalární pole
|
||||
fixed_keys = {c[0] for c in FIXED_COLS}
|
||||
extra_keys = set()
|
||||
for doc in docs:
|
||||
for k in doc.keys():
|
||||
if k not in fixed_keys and k not in SKIP_KEYS:
|
||||
extra_keys.add(k)
|
||||
extra_keys = sorted(extra_keys)
|
||||
|
||||
ALL_COLS = FIXED_COLS + [(k, k) for k in extra_keys]
|
||||
|
||||
# --- Barvy podle KROK ---
|
||||
def krok_color(krok):
|
||||
if not krok:
|
||||
return None
|
||||
k = krok.strip()
|
||||
if k.startswith("5") or k.startswith("6") or k.startswith("7"):
|
||||
return "FFC6EFCE" # zelená - CDA podepsáno / SIPIQ
|
||||
if k.startswith("4"):
|
||||
return "FFB7E1CD" # tmavší zelená - CDA vyžádáno
|
||||
if k.startswith("3.1"):
|
||||
return "FFDDEBF7" # světle modrá - zájem
|
||||
if k.startswith("3.2"):
|
||||
return "FFFFC7CE" # červená - nezájem
|
||||
if k.startswith("2"):
|
||||
return "FFFFF2CC" # světle žlutá - připomenuto
|
||||
if k.startswith("1"):
|
||||
return "FFDCE6F1" # modrá - nabídka odeslána
|
||||
if k.startswith("0"):
|
||||
return "FFD9D9D9" # šedá - mimo
|
||||
return None
|
||||
|
||||
# --- Vytvoření workbooku ---
|
||||
wb = openpyxl.Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "Investigators"
|
||||
|
||||
# Styly
|
||||
header_font = Font(bold=True, color="FFFFFFFF")
|
||||
header_fill = PatternFill("solid", fgColor="FF1F4E79")
|
||||
header_align = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||
cell_align = Alignment(vertical="top", wrap_text=True)
|
||||
thin = Side(style="thin", color="FFB0B0B0")
|
||||
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
||||
|
||||
# Záhlaví
|
||||
for col_idx, (key, label) in enumerate(ALL_COLS, 1):
|
||||
cell = ws.cell(row=1, column=col_idx, value=label)
|
||||
cell.font = header_font
|
||||
cell.fill = header_fill
|
||||
cell.alignment = header_align
|
||||
cell.border = border
|
||||
|
||||
ws.row_dimensions[1].height = 30
|
||||
|
||||
# Data
|
||||
for row_idx, doc in enumerate(docs, 2):
|
||||
krok_val = str(doc.get("KROK", "") or "")
|
||||
bg = krok_color(krok_val)
|
||||
|
||||
for col_idx, (key, label) in enumerate(ALL_COLS, 1):
|
||||
val = doc.get(key, "")
|
||||
# Převod na string pokud je list nebo dict
|
||||
if isinstance(val, list):
|
||||
val = ", ".join(str(v) for v in val)
|
||||
elif isinstance(val, dict):
|
||||
val = str(val)
|
||||
elif val is None:
|
||||
val = ""
|
||||
else:
|
||||
val = str(val)
|
||||
|
||||
cell = ws.cell(row=row_idx, column=col_idx, value=val)
|
||||
cell.alignment = cell_align
|
||||
cell.border = border
|
||||
|
||||
if bg:
|
||||
cell.fill = PatternFill("solid", fgColor=bg)
|
||||
if key == "KROK":
|
||||
cell.font = Font(bold=True)
|
||||
|
||||
# Šířky sloupců
|
||||
col_widths = {
|
||||
"prijmeni": 18, "jmeno": 15, "email": 35,
|
||||
"KROK": 26, "STATUS": 45, "kriticka_poznamka": 60,
|
||||
"zeme": 12, "pracoviste": 35, "internet_summary": 60,
|
||||
}
|
||||
for col_idx, (key, label) in enumerate(ALL_COLS, 1):
|
||||
w = col_widths.get(key, 20)
|
||||
ws.column_dimensions[get_column_letter(col_idx)].width = w
|
||||
|
||||
# Zmrazení záhlaví
|
||||
ws.freeze_panes = "A2"
|
||||
|
||||
# Autofilter
|
||||
ws.auto_filter.ref = ws.dimensions
|
||||
|
||||
# Uložení
|
||||
wb.save(filepath)
|
||||
print(f"Ulozeno: {filepath}")
|
||||
print("Poradi sloupcu:", [label for _, label in ALL_COLS][:6], "...")
|
||||
@@ -0,0 +1,30 @@
|
||||
# store_cda_batch_v1.0.py
|
||||
|
||||
**Verze:** 1.0 · **Datum:** 2026-06-09
|
||||
|
||||
Dávkové uložení binárek CDA (PDF) do Mongo `feasibility.investigators` →
|
||||
`cda.data_*`. Zdroj = `.msg` soubory na Toweru (`/mnt/user/JNJEMAILS`),
|
||||
stažené přes SFTP (paramiko), příloha vytažena `extract_msg`.
|
||||
|
||||
## Princip
|
||||
- `MAPPING` = explicitní seznam `(investigator_id, msg_filename,
|
||||
attachment_filename, label)` — žádné hádání za běhu (matchování přílohy v `.msg`
|
||||
přes normalizaci bez diakritiky).
|
||||
- CDA chodí od 3 asistentek: **Wittenbergerová** (LWittenb), **Hrabalová**
|
||||
(LHrabalo), **Vojčová** (LVojcova). Konkrétní soubor bývá jmenován v STATUS lékaře.
|
||||
|
||||
## Co zapisuje
|
||||
`cda.data_base64`, `cda.data_sha256`, `cda.data_filename`, `cda.data_mime`,
|
||||
`cda.data_size`, `cda.data_stored_at`, `cda.data_source_msg`; doplní `cda.soubor`.
|
||||
|
||||
## Spuštění
|
||||
```
|
||||
python store_cda_batch_v1.0.py # dry-run / náhled
|
||||
python store_cda_batch_v1.0.py --apply # zápis do Mongo
|
||||
```
|
||||
venv má `paramiko` + `extract_msg` + `pymongo`.
|
||||
|
||||
## Historie
|
||||
- v1.0 — dávka 1 (6×): Hlavatý/Cliniq, Fedurco/ENDOMED, Tichý, Falc, Pešta,
|
||||
Jungwirthová. Dávka 2 (3×): Matouš/Axon-master, Mihálkanin/Gastro LM,
|
||||
Krížová/FN Motol. Aplikováno 09JUN2026. (Lukáč zvlášť přes store_cda_to_mongo.)
|
||||
@@ -0,0 +1,145 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: store_cda_batch_v1.0.py
|
||||
# Verze: 1.0
|
||||
# Datum: 2026-06-09
|
||||
# Popis: Davkove ulozi binarky CDA (PDF) do Mongo k investigatorum
|
||||
# (feasibility.investigators -> cda.data_*). Zdroj = .msg soubory na
|
||||
# Toweru (/mnt/user/JNJEMAILS), stazene pres SFTP, priloha vytazena
|
||||
# extract_msg. Mapovani investigator -> (.msg, attachment) je
|
||||
# explicitni (zadne hadani za behu). Drzi se domluvy: fyzicky
|
||||
# dokument z e-mailu -> do Mongo.
|
||||
# Zapise: cda.data_base64, cda.data_sha256, cda.data_filename,
|
||||
# cda.data_mime, cda.data_size, cda.data_stored_at,
|
||||
# cda.data_source_msg; doplni cda.soubor pokud chybi.
|
||||
# Existujici cda.* (stav, datum_*, zdroj, poznamka) NEMENI.
|
||||
# Pouziti: python store_cda_batch_v1.0.py (dry-run / nahled)
|
||||
# python store_cda_batch_v1.0.py --apply (zapise do Mongo)
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import sys
|
||||
import base64
|
||||
import hashlib
|
||||
import unicodedata
|
||||
import paramiko
|
||||
import extract_msg
|
||||
from pymongo import MongoClient
|
||||
from bson import ObjectId
|
||||
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://192.168.1.76:27017")
|
||||
TOWER_HOST = "192.168.1.76"
|
||||
TOWER_USER = "root"
|
||||
TOWER_PASS = "7309208104"
|
||||
REMOTE_DIR = "/mnt/user/JNJEMAILS"
|
||||
TMPDIR = r"u:\Dropbox\!!!Days\Downloads Z230\_cda_tmp"
|
||||
STORED_AT = "2026-06-09"
|
||||
|
||||
# investigator_id -> (msg_filename, attachment_filename, label)
|
||||
# DAVKA 2 (09JUN2026): institucionalni CDA, soubor jmenovan primo v STATUS lekare
|
||||
MAPPING = [
|
||||
("6a19832b5fc2213518257950", "FC130007D8A1F0E30000.msg",
|
||||
"CZ_CDA Template Master institution_Axon Clinical, s.r.o._fully signed 08Jun2026.pdf",
|
||||
"Matous Jan (AXON Clinical, master)"),
|
||||
("6a19832b5fc2213518257958", "FC130007D8A1F0E60000.msg",
|
||||
"SK_CDA institution_Gastro LM_fully signed_08Jun2026.pdf",
|
||||
"Mihalkanin Lubomir (Gastro LM)"),
|
||||
("6a198b661218c31ab0f5ba4e", "FC130007C1643CA10000.msg",
|
||||
"06_CDA-Janssen a FN v Motole_fully executed.pdf",
|
||||
"Krizova Viera (FN Motol master)"),
|
||||
]
|
||||
|
||||
# DAVKA 1 (09JUN2026) - jiz ulozeno, ponechano pro historii:
|
||||
# Hlavaty/Cliniq FC1300053049739C, Fedurco/ENDOMED FC1300053049739B,
|
||||
# Tichy FC13000530495B95, Falc FC130007D8A1F0E6, Pesta FC130007D8A1F0E1,
|
||||
# Jungwirthova FC130007D8A1F0E2, Lukac FC130007C9E971FF (store_cda_to_mongo_v1.0)
|
||||
|
||||
|
||||
def norm(s):
|
||||
"""lowercase, bez diakritiky, sjednocene mezery"""
|
||||
s = s or ""
|
||||
s = unicodedata.normalize("NFKD", s)
|
||||
s = "".join(c for c in s if not unicodedata.combining(c))
|
||||
return " ".join(s.lower().split())
|
||||
|
||||
|
||||
def main():
|
||||
apply = "--apply" in sys.argv
|
||||
os.makedirs(TMPDIR, exist_ok=True)
|
||||
|
||||
# SSH/SFTP
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect(TOWER_HOST, username=TOWER_USER, password=TOWER_PASS, timeout=30)
|
||||
sftp = ssh.open_sftp()
|
||||
|
||||
client = MongoClient(MONGO_URI)
|
||||
col = client["feasibility"]["investigators"]
|
||||
|
||||
plan = []
|
||||
for inv_id, msg_name, att_name, label in MAPPING:
|
||||
local_msg = os.path.join(TMPDIR, msg_name)
|
||||
if not os.path.exists(local_msg):
|
||||
sftp.get(f"{REMOTE_DIR}/{msg_name}", local_msg)
|
||||
m = extract_msg.Message(local_msg)
|
||||
target = norm(att_name)
|
||||
chosen = None
|
||||
for att in m.attachments:
|
||||
name = att.longFilename or att.shortFilename or ""
|
||||
if norm(name) == target or (target in norm(name)) or (norm(name) in target and name.lower().endswith(".pdf")):
|
||||
chosen = (name, att.data)
|
||||
break
|
||||
m.close()
|
||||
if not chosen:
|
||||
plan.append((inv_id, label, msg_name, att_name, None, "!!! PRILOHA NENALEZENA"))
|
||||
continue
|
||||
raw = chosen[1]
|
||||
sha = hashlib.sha256(raw).hexdigest()
|
||||
plan.append((inv_id, label, msg_name, chosen[0], (len(raw), sha, raw), "OK"))
|
||||
|
||||
sftp.close(); ssh.close()
|
||||
|
||||
# Nahled
|
||||
print("=== NAHLED DAVKY (CDA -> Mongo cda.data) ===\n")
|
||||
for inv_id, label, msg_name, att_name, info, status in plan:
|
||||
doc = col.find_one({"_id": ObjectId(inv_id)}, {"prijmeni": 1, "jmeno": 1, "cda.data_base64": 1})
|
||||
has = bool(doc and doc.get("cda", {}).get("data_base64"))
|
||||
print(f"[{status}] {label} (_id {inv_id})")
|
||||
print(f" .msg: {msg_name}")
|
||||
print(f" priloha: {att_name}")
|
||||
if info:
|
||||
print(f" velikost: {info[0]} B sha256: {info[1]}")
|
||||
print(f" data_base64 jiz existuje: {has}")
|
||||
print()
|
||||
|
||||
if not apply:
|
||||
print(">>> DRY-RUN. Pro zapis spust s --apply")
|
||||
return
|
||||
|
||||
n = 0
|
||||
for inv_id, label, msg_name, att_name, info, status in plan:
|
||||
if status != "OK" or not info:
|
||||
print(f"PRESKAKUJI {label}: {status}")
|
||||
continue
|
||||
size, sha, raw = info
|
||||
b64 = base64.b64encode(raw).decode("ascii")
|
||||
res = col.update_one(
|
||||
{"_id": ObjectId(inv_id)},
|
||||
{"$set": {
|
||||
"cda.data_base64": b64,
|
||||
"cda.data_sha256": sha,
|
||||
"cda.data_filename": att_name,
|
||||
"cda.data_mime": "application/pdf",
|
||||
"cda.data_size": size,
|
||||
"cda.data_stored_at": STORED_AT,
|
||||
"cda.data_source_msg": msg_name,
|
||||
"cda.soubor": att_name,
|
||||
}},
|
||||
)
|
||||
n += res.modified_count
|
||||
print(f"ZAPSANO: {label} (modified={res.modified_count})")
|
||||
print(f"\n>>> CELKEM ZAPSANO: {n}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,26 @@
|
||||
# store_cda_to_mongo_v1.0.py
|
||||
|
||||
**Verze:** 1.0 · **Datum:** 2026-06-09
|
||||
|
||||
Uloží binárku jednoho dokumentu (CDA PDF) z lokálního souboru do Mongo
|
||||
`feasibility.investigators` k danému lékaři do pole `cda.data_*`. Drží se
|
||||
domluvy: fyzický dokument z e-mailu → do Mongo.
|
||||
|
||||
## Co zapisuje
|
||||
`cda.data_base64`, `cda.data_sha256`, `cda.data_filename`, `cda.data_mime`,
|
||||
`cda.data_size`, `cda.data_stored_at`. Existující `cda.*` (stav, datum_*, soubor,
|
||||
zdroj, poznamka) **nemění**.
|
||||
|
||||
## Konfigurace (v hlavičce skriptu)
|
||||
`INVESTIGATOR_ID`, `PDF_PATH`, `DATA_FILENAME`, `DATA_MIME`, `STORED_AT`.
|
||||
|
||||
## Spuštění
|
||||
```
|
||||
python store_cda_to_mongo_v1.0.py # dry-run / náhled
|
||||
python store_cda_to_mongo_v1.0.py --apply # zápis do Mongo
|
||||
```
|
||||
venv: `U:\PythonProject\Janssen\.venv\Scripts\python.exe`
|
||||
|
||||
## Historie
|
||||
- v1.0 — Lukáč Ľudovít (aplikováno 09JUN2026). PDF extrahováno z `.msg`
|
||||
`FC130007C9E971FF0000.msg` (Tower `/mnt/user/JNJEMAILS`).
|
||||
@@ -0,0 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: store_cda_to_mongo_v1.0.py
|
||||
# Verze: 1.0
|
||||
# Datum: 2026-06-09
|
||||
# Popis: Ulozi binarku dokumentu (napr. CDA PDF) do Mongo k investigatorovi
|
||||
# (feasibility.investigators -> pole cda.data_*). Drzi se domluvy:
|
||||
# "fyzicky dokument z e-mailu -> do Mongo".
|
||||
# Zdroj dat = lokalni soubor (PDF uz extrahovany z .msg).
|
||||
# Zapise: cda.data_base64, cda.data_sha256, cda.data_filename,
|
||||
# cda.data_mime, cda.data_size, cda.data_stored_at.
|
||||
# Existujici cda.* (stav, datum_*, soubor, zdroj, poznamka) NEMENI.
|
||||
# Pouziti: python store_cda_to_mongo_v1.0.py (dry-run / nahled)
|
||||
# python store_cda_to_mongo_v1.0.py --apply (zapise do Mongo)
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import sys
|
||||
import base64
|
||||
import hashlib
|
||||
from pymongo import MongoClient
|
||||
from bson import ObjectId
|
||||
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://192.168.1.76:27017")
|
||||
|
||||
# --- Konfigurace konkretniho zapisu ---
|
||||
INVESTIGATOR_ID = "6a1c4275aa46d8b608065cec" # Lukac Ludovit
|
||||
PDF_PATH = r"u:\Dropbox\!!!Days\Downloads Z230\SK_CDA_ PI_doc. MUDr. Ludovít Lukác, Ph.D._fully signed_04Jun2026.pdf"
|
||||
DATA_FILENAME = "SK_CDA_ PI_doc. MUDr. Ľudovít Lukáč, Ph.D._fully signed_04Jun2026.pdf"
|
||||
DATA_MIME = "application/pdf"
|
||||
STORED_AT = "2026-06-09" # datum ulozeni (date nelze generovat za behu)
|
||||
|
||||
|
||||
def main():
|
||||
apply = "--apply" in sys.argv
|
||||
|
||||
if not os.path.exists(PDF_PATH):
|
||||
print("!!! Soubor neexistuje:", PDF_PATH)
|
||||
return
|
||||
with open(PDF_PATH, "rb") as f:
|
||||
raw = f.read()
|
||||
size = len(raw)
|
||||
sha = hashlib.sha256(raw).hexdigest()
|
||||
b64 = base64.b64encode(raw).decode("ascii")
|
||||
|
||||
client = MongoClient(MONGO_URI)
|
||||
col = client["feasibility"]["investigators"]
|
||||
doc = col.find_one({"_id": ObjectId(INVESTIGATOR_ID)},
|
||||
{"prijmeni": 1, "jmeno": 1, "cda": 1})
|
||||
if not doc:
|
||||
print("!!! Investigator nenalezen:", INVESTIGATOR_ID)
|
||||
return
|
||||
|
||||
print("=== NAHLED ZAPISU ===")
|
||||
print(f"Investigator: {doc.get('prijmeni')} {doc.get('jmeno')} (_id {INVESTIGATOR_ID})")
|
||||
cda = doc.get("cda", {}) or {}
|
||||
print("Stavajici cda.* pole:", ", ".join(sorted(cda.keys())) or "(zadne)")
|
||||
print(" - cda.soubor:", cda.get("soubor"))
|
||||
print(" - cda.velikost_bytes:", cda.get("velikost_bytes"))
|
||||
has_data = "data_base64" in cda
|
||||
print(" - cda.data_base64 jiz existuje:", has_data)
|
||||
print()
|
||||
print("PRIDAM/PREPISI tato pole:")
|
||||
print(" cda.data_filename =", DATA_FILENAME)
|
||||
print(" cda.data_mime =", DATA_MIME)
|
||||
print(" cda.data_size =", size, "B")
|
||||
print(" cda.data_sha256 =", sha)
|
||||
print(" cda.data_stored_at=", STORED_AT)
|
||||
print(f" cda.data_base64 = <base64 {len(b64)} znaku>")
|
||||
print()
|
||||
|
||||
if not apply:
|
||||
print(">>> DRY-RUN. Pro zapis spust s --apply")
|
||||
return
|
||||
|
||||
res = col.update_one(
|
||||
{"_id": ObjectId(INVESTIGATOR_ID)},
|
||||
{"$set": {
|
||||
"cda.data_base64": b64,
|
||||
"cda.data_sha256": sha,
|
||||
"cda.data_filename": DATA_FILENAME,
|
||||
"cda.data_mime": DATA_MIME,
|
||||
"cda.data_size": size,
|
||||
"cda.data_stored_at": STORED_AT,
|
||||
}},
|
||||
)
|
||||
print(f">>> ZAPSANO: matched={res.matched_count}, modified={res.modified_count}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,26 @@
|
||||
# store_sipiq_links_v1.0.py
|
||||
|
||||
**Verze:** 1.0 · **Datum:** 2026-06-09
|
||||
|
||||
Uloží unikátní **SIPIQ odkaz** (per-centrum) ke každému investigatorovi do Mongo
|
||||
`feasibility.investigators` → `sipiq.link` (+ `sipiq.link_token`,
|
||||
`sipiq.link_stored_at`, `sipiq.link_source`).
|
||||
|
||||
## Zdroj
|
||||
Trilium note **„SIPIQ"** (noteId `hAMNUnUQdCRn`) — seznam „lékař → link".
|
||||
Odkaz je pro každé centrum jedinečný (liší se `Q_DL` = `EMD_…_CGC_…`),
|
||||
survey ID je u všech stejné `SV_9AdeNaNyohp5fNQ`.
|
||||
|
||||
## Mapování
|
||||
`MAPPING` = explicitní `(investigator_id, label, Q_DL token)` pro 14 lékařů
|
||||
v kroku 5 (CDA podepsáno). Plný link se skládá přes `BASE % token`.
|
||||
|
||||
## Spuštění
|
||||
```
|
||||
python store_sipiq_links_v1.0.py # dry-run / náhled
|
||||
python store_sipiq_links_v1.0.py --apply # zápis do Mongo
|
||||
```
|
||||
venv: `U:\PythonProject\Janssen\.venv\Scripts\python.exe`
|
||||
|
||||
## Historie
|
||||
- v1.0 — 14 linků uloženo 09JUN2026.
|
||||
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# =============================================================================
|
||||
# Nazev: store_sipiq_links_v1.0.py
|
||||
# Verze: 1.0
|
||||
# Datum: 2026-06-09
|
||||
# Popis: Ulozi unikatni SIPIQ odkaz (per-centrum) ke kazdemu investigatorovi
|
||||
# do Mongo feasibility.investigators -> pole sipiq.link
|
||||
# (+ sipiq.link_stored_at, sipiq.link_source). Zdroj = Trilium note
|
||||
# "SIPIQ" (noteId hAMNUnUQdCRn). Mapovani investigator->link je
|
||||
# explicitni. 14 lekaru v kroku 5 (CDA podepsano).
|
||||
# Pouziti: python store_sipiq_links_v1.0.py (dry-run / nahled)
|
||||
# python store_sipiq_links_v1.0.py --apply (zapise do Mongo)
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pymongo import MongoClient
|
||||
from bson import ObjectId
|
||||
|
||||
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://192.168.1.76:27017")
|
||||
STORED_AT = "2026-06-09"
|
||||
SOURCE = "Trilium note SIPIQ (hAMNUnUQdCRn)"
|
||||
BASE = "https://janssenfeasibility.iad1.qualtrics.com/jfe/form/SV_9AdeNaNyohp5fNQ?Q_CHL=gl&Q_DL=%s&_g_=g"
|
||||
|
||||
# investigator_id -> (label, Q_DL token)
|
||||
MAPPING = [
|
||||
("6a1c4275aa46d8b608065cec", "Lukac Ludovit", "EMD_t2InaXAmvYtCEIT_9AdeNaNyohp5fNQ_CGC_pcjxC6AEA9hxsHl"),
|
||||
("6a19832b5fc221351825794f", "Hlavaty Tibor", "EMD_xmPsx66DQKz3z7M_9AdeNaNyohp5fNQ_CGC_wR6sCr6EmyO4oKq"),
|
||||
("6a19832b5fc2213518257954", "Fedurco Miroslav", "EMD_ZcpPzkNPT9V9pcJ_9AdeNaNyohp5fNQ_CGC_rWQC2OGTV3TaRQx"),
|
||||
("6a198b661218c31ab0f5ba43", "Tichy Michal", "EMD_Cwv9ZT1PSVn3hMb_9AdeNaNyohp5fNQ_CGC_BaZnCP2pwlmbMpX"),
|
||||
("6a19832b5fc221351825796e", "Falc Matej", "EMD_eUNAj2vPihHOm7g_9AdeNaNyohp5fNQ_CGC_aLo6pEBRHwMmLUg"),
|
||||
("6a198b661218c31ab0f5ba41", "Pesta Martin", "EMD_ykhyDJzyGYbwNlV_9AdeNaNyohp5fNQ_CGC_k6q3Vh4womEdc9s"),
|
||||
("6a198b661218c31ab0f5ba45", "Jungwirthova Anna", "EMD_f41v8N8wB7T5xUa_9AdeNaNyohp5fNQ_CGC_lW8THoTh7nYXYrn"),
|
||||
("6a19832b5fc2213518257950", "Matous Jan", "EMD_N5N7KrQwv4kI6uS_9AdeNaNyohp5fNQ_CGC_MQXKadWMxdLFhxi"),
|
||||
("6a19832b5fc2213518257958", "Mihalkanin Lubomir", "EMD_LAfWg2NWL3OpvFT_9AdeNaNyohp5fNQ_CGC_nhe5FXQKw8kOzie"),
|
||||
("6a198b661218c31ab0f5ba4e", "Krizova Viera", "EMD_rX6VNRycwqE5Gkw_9AdeNaNyohp5fNQ_CGC_P8peeeBOWsriB9e"),
|
||||
("6a19832b5fc221351825795e", "Stepek David", "EMD_tG1kIyZQVo6m5dX_9AdeNaNyohp5fNQ_CGC_Q1fqrVdGo82akWK"),
|
||||
("6a19832b5fc2213518257972", "Konecny Stefan", "EMD_AQa8HOUS1lQ61Be_9AdeNaNyohp5fNQ_CGC_v9oCwjfwyGIrAPt"),
|
||||
("6a1987481218c31ab0f5ba33", "Svoboda Pavel", "EMD_CjqBu34ODPe7o03_9AdeNaNyohp5fNQ_CGC_4FCgUB19X2tF1zK"),
|
||||
("6a198b661218c31ab0f5ba42", "Kojecky Vladimir", "EMD_zTJJhhRYwb9Z8pO_9AdeNaNyohp5fNQ_CGC_5Z8Ml8qISWSXWFT"),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
apply = "--apply" in sys.argv
|
||||
client = MongoClient(MONGO_URI)
|
||||
col = client["feasibility"]["investigators"]
|
||||
|
||||
print("=== NAHLED: SIPIQ link -> Mongo (sipiq.link) ===\n")
|
||||
n = 0
|
||||
for inv_id, label, token in MAPPING:
|
||||
link = BASE % token
|
||||
doc = col.find_one({"_id": ObjectId(inv_id)}, {"prijmeni": 1, "jmeno": 1, "sipiq.link": 1})
|
||||
if not doc:
|
||||
print(f"!!! NENALEZEN {label} ({inv_id})")
|
||||
continue
|
||||
existing = (doc.get("sipiq") or {}).get("link")
|
||||
print(f"{label:22s} token={token[:24]}... existuje={'ANO' if existing else 'ne'}")
|
||||
if apply:
|
||||
res = col.update_one(
|
||||
{"_id": ObjectId(inv_id)},
|
||||
{"$set": {
|
||||
"sipiq.link": link,
|
||||
"sipiq.link_token": token,
|
||||
"sipiq.link_stored_at": STORED_AT,
|
||||
"sipiq.link_source": SOURCE,
|
||||
}},
|
||||
)
|
||||
n += res.modified_count
|
||||
|
||||
print()
|
||||
if apply:
|
||||
print(f">>> ZAPSANO: {n} zaznamu")
|
||||
else:
|
||||
print(">>> DRY-RUN. Pro zapis spust s --apply")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user