#!/usr/bin/env python3 # -*- coding: utf-8 -*- import pymysql import requests from pathlib import Path from datetime import datetime from dateutil import parser import time import sys # ================================ # UTF-8 SAFE 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') def safe_print(text: str): enc = sys.stdout.encoding or "" if not enc.lower().startswith("utf"): text = ''.join(ch for ch in text if ord(ch) < 65536) try: print(text) except UnicodeEncodeError: text = ''.join(ch for ch in text if ord(ch) < 128) print(text) # ================================ # 🔧 CONFIG # ================================ TOKEN_PATH = Path("token.txt") CLINIC_SLUG = "mudr-buzalkova" BATCH_SIZE = 500 STATES = ["ACTIVE", "DONE"] # explicitně – jinak API vrací jen ACTIVE DB_CONFIG = { "host": "192.168.1.50", "port": 3306, "user": "root", "password": "Vlado9674+", "database": "medevio", "charset": "utf8mb4", "cursorclass": pymysql.cursors.DictCursor, } GRAPHQL_QUERY = r""" query ClinicRequestList2( $clinicSlug: String!, $queueId: String, $queueAssignment: QueueAssignmentFilter!, $state: PatientRequestState, $pageInfo: PageInfo!, $locale: Locale! ) { requestsResponse: listPatientRequestsForClinic2( clinicSlug: $clinicSlug, queueId: $queueId, queueAssignment: $queueAssignment, state: $state, pageInfo: $pageInfo ) { count patientRequests { id displayTitle(locale: $locale) createdAt updatedAt doneAt removedAt extendedPatient { name surname identificationNumber } lastMessage { createdAt } } } } """ # ================================ # TOKEN # ================================ def read_token(path: Path) -> str: tok = path.read_text(encoding="utf-8").strip() if tok.startswith("Bearer "): return tok.split(" ", 1)[1] return tok # ================================ # DATETIME PARSER # ================================ def to_mysql_dt(iso_str): if not iso_str: return None try: dt = parser.isoparse(iso_str) if dt.tzinfo is None: dt = dt.replace(tzinfo=datetime.now().astimezone().tzinfo) return dt.astimezone().strftime("%Y-%m-%d %H:%M:%S") except Exception: return None # ================================ # UPSERT # ================================ def upsert(conn, r): p = r.get("extendedPatient") or {} api_updated = to_mysql_dt(r.get("updatedAt")) msg_updated = to_mysql_dt((r.get("lastMessage") or {}).get("createdAt")) final_updated = max(filter(None, [api_updated, msg_updated]), default=None) sql = """ INSERT INTO pozadavky ( id, displayTitle, createdAt, updatedAt, doneAt, removedAt, pacient_jmeno, pacient_prijmeni, pacient_rodnecislo ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s) ON DUPLICATE KEY UPDATE displayTitle=VALUES(displayTitle), updatedAt=VALUES(updatedAt), doneAt=VALUES(doneAt), removedAt=VALUES(removedAt), pacient_jmeno=VALUES(pacient_jmeno), pacient_prijmeni=VALUES(pacient_prijmeni), pacient_rodnecislo=VALUES(pacient_rodnecislo) """ vals = ( r.get("id"), r.get("displayTitle"), to_mysql_dt(r.get("createdAt")), final_updated, to_mysql_dt(r.get("doneAt")), to_mysql_dt(r.get("removedAt")), p.get("name"), p.get("surname"), p.get("identificationNumber"), ) with conn.cursor() as cur: cur.execute(sql, vals) conn.commit() # ================================ # FETCH PAGE (per state) # ================================ def fetch_state(headers, state, offset): variables = { "clinicSlug": CLINIC_SLUG, "queueId": None, "queueAssignment": "ANY", "state": state, "pageInfo": {"first": BATCH_SIZE, "offset": offset}, "locale": "cs", } payload = { "operationName": "ClinicRequestList2", "query": GRAPHQL_QUERY, "variables": variables, } r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers) r.raise_for_status() data = r.json()["data"]["requestsResponse"] return data.get("patientRequests", []), data.get("count", 0) # ================================ # MAIN # ================================ def main(): token = read_token(TOKEN_PATH) headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json", } conn = pymysql.connect(**DB_CONFIG) safe_print(f"\n=== FULL Medevio READ-ALL sync @ {datetime.now():%Y-%m-%d %H:%M:%S} ===") grand_total = 0 for state in STATES: safe_print(f"\n🔁 STATE = {state}") offset = 0 total = None processed = 0 while True: batch, count = fetch_state(headers, state, offset) if total is None: total = count safe_print(f"📡 {state}: celkem {total}") if not batch: break for r in batch: upsert(conn, r) processed += len(batch) safe_print(f" • {processed}/{total}") offset += BATCH_SIZE if offset >= count: break time.sleep(0.4) grand_total += processed conn.close() safe_print(f"\n✅ HOTOVO – celkem zpracováno {grand_total} požadavků\n") # ================================ if __name__ == "__main__": main()