Fix agenda report and add MySQL sync for open requests

- 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>
This commit is contained in:
2026-03-10 07:44:19 +01:00
parent 7c08ad8e35
commit be0d41ad01
4 changed files with 301 additions and 18 deletions

View File

@@ -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}")