- 871 test.py: Switch auth from medevio_storage.json to token.txt, update MySQL port to 3306, add hyperlinks to Request_ID column, add better API error handling - sync_open_requests.py: New script to sync doneAt/removedAt/updatedAt from Medevio API to MySQL for requests incorrectly marked as open - check_request.py: Diagnostic script to inspect a single request via API - check_mysql.py: Diagnostic script to inspect a single request in MySQL Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
179 lines
5.0 KiB
Python
179 lines
5.0 KiB
Python
#!/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}")
|