diff --git a/40 agenda a požadavky/871 test.py b/40 agenda a požadavky/871 test.py index 909ae11..dab86c2 100644 --- a/40 agenda a požadavky/871 test.py +++ b/40 agenda a požadavky/871 test.py @@ -30,7 +30,7 @@ CLINIC_SLUG = "mudr-buzalkova" DB_CONFIG = { "host": "192.168.1.76", - "port": 3307, + "port": 3306, "user": "root", "password": "Vlado9674+", "database": "medevio", @@ -40,26 +40,22 @@ DB_CONFIG = { EXPORT_DIR = Path(r"u:\Dropbox\Ordinace\Reporty") EXPORT_DIR.mkdir(exist_ok=True, parents=True) -timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") -xlsx_path = EXPORT_DIR / f"{timestamp} Agenda + Pozadavky (Merged).xlsx" + +# Delete previous reports +for old in EXPORT_DIR.glob("* Agenda + Požadavky.xlsx"): + old.unlink() + print(f"🗑️ Deleted old report: {old.name}") + +timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S") +xlsx_path = EXPORT_DIR / f"{timestamp} Agenda + Požadavky.xlsx" # ==================== LOAD TOKEN ==================== -def load_gateway_token(storage_path="medevio_storage.json"): - path = Path(storage_path) - if not path.exists(): - raise SystemExit(f"❌ Storage file not found: {path}") - with path.open("r", encoding="utf-8") as f: - state = json.load(f) - token = next( - (c["value"] for c in state["cookies"] if c["name"] == "gateway-access-token"), - None, - ) - if not token: - raise SystemExit("❌ gateway-access-token not found in storage file.") - return token - - -gateway_token = load_gateway_token() +TOKEN_PATH = Path("token.txt") +if not TOKEN_PATH.exists(): + TOKEN_PATH = Path(__file__).parent / "token.txt" +if not TOKEN_PATH.exists(): + raise SystemExit(f"❌ token.txt not found") +gateway_token = TOKEN_PATH.read_text(encoding="utf-8").strip() headers = { "content-type": "application/json", @@ -80,8 +76,18 @@ thin_border = Border( ) +REQUEST_URL_TEMPLATE = "https://my.medevio.cz/mudr-buzalkova/klinika/pozadavky?pozadavek={}" +link_font = Font(color="0563C1", underline="single") + + def format_ws(ws, df): """Apply unified formatting to a worksheet.""" + # Find Request_ID column index (1-based) + req_id_col = None + columns = list(df.columns) + if "Request_ID" in columns: + req_id_col = columns.index("Request_ID") + 1 + for col_idx in range(1, len(df.columns) + 1): col_letter = get_column_letter(col_idx) cell = ws.cell(row=1, column=col_idx) @@ -96,6 +102,10 @@ def format_ws(ws, df): cell.border = thin_border if r_idx % 2 == 0: cell.fill = alt_fill + # Add hyperlink to Request_ID cells + if req_id_col and cell.column == req_id_col and cell.value: + cell.hyperlink = REQUEST_URL_TEMPLATE.format(cell.value) + cell.font = link_font ws.freeze_panes = "A2" @@ -138,7 +148,12 @@ payload = { r = requests.post(GRAPHQL_URL, headers=headers, data=json.dumps(payload)) r.raise_for_status() -reservations = r.json()["data"]["reservations"] +resp = r.json() +if "errors" in resp or "data" not in resp: + print("❌ API response:") + print(json.dumps(resp, indent=2, ensure_ascii=False)) + raise SystemExit("API call failed - check token or query.") +reservations = resp["data"]["reservations"] rows = [] for r in reservations: diff --git a/40 agenda a požadavky/check_mysql.py b/40 agenda a požadavky/check_mysql.py new file mode 100644 index 0000000..df344ad --- /dev/null +++ b/40 agenda a požadavky/check_mysql.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Check one request in MySQL.""" + +import pymysql +import json + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +REQUEST_ID = "6b46b5a8-b080-4821-86b0-39adabeec86b" + +conn = pymysql.connect(**DB_CONFIG) +with conn.cursor() as cur: + cur.execute("SELECT * FROM pozadavky WHERE id = %s", (REQUEST_ID,)) + row = cur.fetchone() +conn.close() + +if row: + # Convert datetime objects to strings for JSON serialization + for k, v in row.items(): + if hasattr(v, 'isoformat'): + row[k] = v.isoformat() + print(json.dumps(row, indent=2, ensure_ascii=False, default=str)) +else: + print(f"Not found: {REQUEST_ID}") diff --git a/40 agenda a požadavky/check_request.py b/40 agenda a požadavky/check_request.py new file mode 100644 index 0000000..4acbed4 --- /dev/null +++ b/40 agenda a požadavky/check_request.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Quick check: fetch one request from Medevio API and print all fields.""" + +import json +import requests +from pathlib import Path + +TOKEN_PATH = Path(__file__).parent / "token.txt" +GRAPHQL_URL = "https://api.medevio.cz/graphql" +CLINIC_SLUG = "mudr-buzalkova" +REQUEST_ID = "6b46b5a8-b080-4821-86b0-39adabeec86b" + +token = TOKEN_PATH.read_text(encoding="utf-8").strip() +headers = { + "content-type": "application/json", + "authorization": f"Bearer {token}", + "origin": "https://my.medevio.cz", + "referer": "https://my.medevio.cz/", +} + +# Query with as many fields as possible +QUERY = """ +query GetPatientRequest2($requestId: UUID!, $clinicSlug: String!, $locale: Locale!) { + request: getPatientRequest2(patientRequestId: $requestId, clinicSlug: $clinicSlug) { + id + displayTitle(locale: $locale) + createdAt + updatedAt + doneAt + removedAt + userNote + eventType + extendedPatient(clinicSlug: $clinicSlug) { + name + surname + dob + identificationNumber + insuranceCompanyObject { shortName } + } + ecrfFilledData(locale: $locale) { + name + groups { + label + fields { name label type value } + } + } + } +} +""" + +payload = { + "operationName": "GetPatientRequest2", + "query": QUERY, + "variables": { + "requestId": REQUEST_ID, + "clinicSlug": CLINIC_SLUG, + "locale": "cs", + }, +} + +r = requests.post(GRAPHQL_URL, json=payload, headers=headers, timeout=30) +print(json.dumps(r.json(), indent=2, ensure_ascii=False)) diff --git a/40 agenda a požadavky/sync_open_requests.py b/40 agenda a požadavky/sync_open_requests.py new file mode 100644 index 0000000..2c063f3 --- /dev/null +++ b/40 agenda a požadavky/sync_open_requests.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Sync open requests: checks each request marked as open in MySQL (doneAt IS NULL +AND removedAt IS NULL) against the Medevio API. If the API shows the request is +closed (doneAt) or removed (removedAt), updates MySQL accordingly. +""" + +import json +import sys +import time +import requests +import pymysql +from pathlib import Path +from datetime import datetime + +# ============================== +# UTF-8 output (Windows friendly) +# ============================== +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +# ============================== +# DRY RUN - set to True to only print what would be updated, False to actually update +# ============================== +DRY_RUN = False + +# ============================== +# CONFIG +# ============================== +GRAPHQL_URL = "https://api.medevio.cz/graphql" +CLINIC_SLUG = "mudr-buzalkova" + +TOKEN_PATH = Path(__file__).parent / "token.txt" +if not TOKEN_PATH.exists(): + raise SystemExit("❌ token.txt not found") + +gateway_token = TOKEN_PATH.read_text(encoding="utf-8").strip() +headers = { + "content-type": "application/json", + "authorization": f"Bearer {gateway_token}", + "origin": "https://my.medevio.cz", + "referer": "https://my.medevio.cz/", +} + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +GRAPHQL_QUERY = """ +query GetPatientRequest2($requestId: UUID!, $clinicSlug: String!) { + request: getPatientRequest2(patientRequestId: $requestId, clinicSlug: $clinicSlug) { + id + doneAt + removedAt + updatedAt + } +} +""" + + +def fix_datetime(dt_str): + if not dt_str: + return None + try: + return datetime.fromisoformat(dt_str.replace("Z", "+00:00")) + except Exception: + return None + + +def fetch_request(request_id): + payload = { + "operationName": "GetPatientRequest2", + "query": GRAPHQL_QUERY, + "variables": { + "requestId": request_id, + "clinicSlug": CLINIC_SLUG, + }, + } + for attempt in range(3): + try: + r = requests.post(GRAPHQL_URL, json=payload, headers=headers, timeout=30) + break + except (requests.ConnectionError, requests.Timeout, requests.exceptions.RequestException) as e: + print(f" ⚠️ Attempt {attempt+1}/3 failed: {e}") + time.sleep(2) + else: + print(f" ❌ Connection failed after 3 attempts for {request_id}") + return None + if r.status_code != 200: + print(f" ❌ HTTP {r.status_code} for {request_id}") + return None + data = r.json() + if "errors" in data: + print(f" ❌ API error for {request_id}: {data['errors']}") + return None + return data.get("data", {}).get("request") + + +# ============================== +# MAIN +# ============================== +conn = pymysql.connect(**DB_CONFIG) + +# 1) Read all open requests from MySQL +with conn.cursor() as cur: + cur.execute( + "SELECT id, displayTitle, pacient_prijmeni, pacient_jmeno " + "FROM pozadavky WHERE doneAt IS NULL AND removedAt IS NULL" + ) + open_requests = cur.fetchall() + +mode = "DRY RUN" if DRY_RUN else "LIVE" +print(f"🔧 Mode: {mode}") +print(f"📋 Found {len(open_requests)} open requests in MySQL.\n") + +updated = 0 +errors = 0 + +for i, req in enumerate(open_requests, 1): + rid = req["id"] + name = f"{req.get('pacient_prijmeni', '')} {req.get('pacient_jmeno', '')}".strip() + title = req.get("displayTitle", "") + print(f"[{i}/{len(open_requests)}] {name} – {title} ({rid})") + + api_data = fetch_request(rid) + if api_data is None: + errors += 1 + continue + + api_done = api_data.get("doneAt") + api_removed = api_data.get("removedAt") + api_updated = api_data.get("updatedAt") + + if api_done or api_removed: + done_dt = fix_datetime(api_done) + removed_dt = fix_datetime(api_removed) + updated_dt = fix_datetime(api_updated) + + status = "DONE" if api_done else "REMOVED" + + if DRY_RUN: + print(f" 🔍 Would update → {status} (doneAt={api_done}, removedAt={api_removed})") + else: + with conn.cursor() as cur: + cur.execute( + "UPDATE pozadavky SET doneAt = %s, removedAt = %s, updatedAt = %s WHERE id = %s", + (done_dt, removed_dt, updated_dt, rid), + ) + conn.commit() + print(f" ✅ Updated → {status}") + + updated += 1 + else: + print(f" ⏳ Still open") + + # Be gentle with the API + time.sleep(1) + +conn.close() + +print(f"\n{'='*50}") +print(f"📊 Total open in MySQL: {len(open_requests)}") +print(f"✅ Updated (closed/removed): {updated}") +print(f"⏳ Still open: {len(open_requests) - updated - errors}") +print(f"❌ Errors: {errors}")