diff --git a/10ReadPozadavky/01 Read pozadavky.py b/10ReadPozadavky/01 Read pozadavky.py new file mode 100644 index 0000000..a2d416f --- /dev/null +++ b/10ReadPozadavky/01 Read pozadavky.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Fetch Medevio pending (ACTIVE) patient requests and return a pandas DataFrame. +Reads Bearer token from token.txt (single line, token only). +""" + +import requests +import pandas as pd +import time +from typing import List, Dict, Any + +# CONFIG --------------------------------------------------------------------- +TOKEN_FILE = "token.txt" # file with token (no "Bearer " prefix) +GRAPHQL_URL = "https://app.medevio.cz/graphql" +CLINIC_SLUG = "mudr-buzalkova" # adjust if needed +LOCALE = "cs" +PAGE_SIZE = 50 # how many items to request per page +REQUEST_WAIT = 0.2 # seconds between requests to be polite +# --------------------------------------------------------------------------- + +GRAPHQL_QUERY = r""" +query ClinicLegacyRequestList_ListPatientRequestsForClinic( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $state: PatientRequestState, + $pageInfo: PageInfo!, + $locale: Locale! +) { + requests: listPatientRequestsForClinic( + clinicSlug: $clinicSlug, + queueId: $queueId, + queueAssignment: $queueAssignment, + state: $state, + pageInfo: $pageInfo + ) { + id + createdAt + dueDate + displayTitle(locale: $locale) + doneAt + removedAt + priority + evaluationResult(locale: $locale) { + fields { + name + value + } + } + clinicId + extendedPatient { + id + identificationNumber + kind + name + note + owner { name surname } + key + status + surname + type + user { id name surname } + isUnknownPatient + } + lastMessage { + createdAt + id + readAt + sender { id name surname clinicId } + text + } + queue { id name } + reservations { id canceledAt done start } + tags(onlyImportant: true) { id name color icon } + priceWhenCreated + currencyWhenCreated + } +} +""" + +def read_token(path: str) -> str: + with open(path, "r", encoding="utf-8") as f: + t = f.read().strip() + if t.startswith("Bearer "): + t = t.split(" ", 1)[1] + return t + +def fetch_requests(token: str, + clinic_slug: str = CLINIC_SLUG, + locale: str = LOCALE, + page_size: int = PAGE_SIZE) -> List[Dict[str, Any]]: + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + all_items: List[Dict[str, Any]] = [] + offset = 0 + + while True: + variables = { + "clinicSlug": clinic_slug, + "queueId": None, + "queueAssignment": "ANY", + "state": "ACTIVE", + "pageInfo": {"first": page_size, "offset": offset}, + "locale": locale, + } + payload = {"query": GRAPHQL_QUERY, "variables": variables, "operationName": "ClinicLegacyRequestList_ListPatientRequestsForClinic"} + + r = requests.post(GRAPHQL_URL, json=payload, headers=headers, timeout=30) + r.raise_for_status() + js = r.json() + + # Basic error handling + if "errors" in js: + raise RuntimeError(f"GraphQL returned errors: {js['errors']}") + + items = js.get("data", {}).get("requests", []) + if not items: + break + + all_items.extend(items) + + # If fewer than requested, we are at the end + if len(items) < page_size: + break + + offset += page_size + time.sleep(REQUEST_WAIT) + + return all_items + +def flatten_item(item: Dict[str, Any]) -> Dict[str, Any]: + patient = item.get("extendedPatient") or {} + last_msg = item.get("lastMessage") or {} + queue = item.get("queue") or {} + + # evaluationResult fields -> map of name:value (if exists) + eval_map = {} + eval_block = item.get("evaluationResult") or {} + for fld in (eval_block.get("fields") or []): + name = fld.get("name") + value = fld.get("value") + if name: + eval_map[name] = value + + flat = { + "id": item.get("id"), + "createdAt": item.get("createdAt"), + "dueDate": item.get("dueDate"), + "displayTitle": item.get("displayTitle"), + "doneAt": item.get("doneAt"), + "removedAt": item.get("removedAt"), + "priority": item.get("priority"), + "clinicId": item.get("clinicId"), + "patient_id": patient.get("id"), + "patient_identificationNumber": patient.get("identificationNumber"), + "patient_name": patient.get("name"), + "patient_surname": patient.get("surname"), + "patient_status": patient.get("status"), + "lastMessage_id": last_msg.get("id"), + "lastMessage_createdAt": last_msg.get("createdAt"), + "lastMessage_text": last_msg.get("text"), + "queue_id": queue.get("id"), + "queue_name": queue.get("name"), + "priceWhenCreated": item.get("priceWhenCreated"), + "currencyWhenCreated": item.get("currencyWhenCreated"), + } + + # merge evaluation fields (if any) prefixed by "eval_" + for k, v in eval_map.items(): + flat[f"eval_{k}"] = v + + return flat + +def to_dataframe(items: List[Dict[str, Any]]) -> pd.DataFrame: + rows = [flatten_item(it) for it in items] + df = pd.DataFrame(rows) + # try parsing dates + for col in ("createdAt", "dueDate", "doneAt", "lastMessage_createdAt", "removedAt"): + if col in df.columns: + df[col] = pd.to_datetime(df[col], errors="coerce") + return df + +def main(): + token = read_token(TOKEN_FILE) + print("Fetching pending (ACTIVE) requests from Medevio...") + items = fetch_requests(token) + print(f"Fetched {len(items)} items.") + df = to_dataframe(items) + pd.set_option("display.max_rows", 20) + pd.set_option("display.max_colwidth", 160) + print(df.head(50)) + # optionally save + df.to_excel("medevio_pending_requests.xlsx", index=False) + print("Saved medevio_pending_requests.xlsx") + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/02 Start query creation.py b/10ReadPozadavky/02 Start query creation.py new file mode 100644 index 0000000..b73968b --- /dev/null +++ b/10ReadPozadavky/02 Start query creation.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json +from pathlib import Path +import requests # 👈 this is new + +# --- Settings ---------------------------------------------------- +TOKEN_PATH = Path("token.txt") # file contains ONLY the token, no "Bearer " +CLINIC_SLUG = "mudr-buzalkova" +SHOW_FULL_TOKEN = False # set True if you want to print the full token +# ----------------------------------------------------------------- + +GRAPHQL_QUERY = r""" +query ClinicLegacyRequestList_ListPatientRequestsForClinic( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $state: PatientRequestState, + $pageInfo: PageInfo!, + $locale: Locale! +) { + requests: listPatientRequestsForClinic( + clinicSlug: $clinicSlug, + queueId: $queueId, + queueAssignment: $queueAssignment, + state: $state, + pageInfo: $pageInfo + ) { + id + createdAt + dueDate + displayTitle(locale: $locale) + doneAt + removedAt + priority + evaluationResult(locale: $locale) { fields { name value } } + clinicId + extendedPatient { + id + identificationNumber + kind + name + surname + status + isUnknownPatient + } + lastMessage { id text createdAt } + queue { id name } + reservations { id canceledAt done start } + tags(onlyImportant: true) { id name color icon } + priceWhenCreated + currencyWhenCreated + } +} +""" + +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +def main(): + token = read_token(TOKEN_PATH) + + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + variables = { + "clinicSlug": CLINIC_SLUG, + "queueId": None, + "queueAssignment": "ANY", + "state": "ACTIVE", # pending / nevyřízené + "pageInfo": {"first": 30, "offset": 0}, + "locale": "cs", + } + + payload = { + "operationName": "ClinicLegacyRequestList_ListPatientRequestsForClinic", + "query": GRAPHQL_QUERY, + "variables": variables, + } + + # === Actually call Medevio API ================================== + print("📡 Querying Medevio GraphQL API...\n") + url = "https://api.medevio.cz/graphql" + r = requests.post(url, json=payload, headers=headers) + print(f"HTTP status: {r.status_code}\n") + + # --- Try to decode JSON + try: + data = r.json() + print("=== Raw JSON response ===") + print(json.dumps(data, indent=2, ensure_ascii=False)) + except Exception as e: + print("❌ Failed to decode JSON:", e) + print("Raw text:\n", r.text) + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/03 Read pozadavek simple.py b/10ReadPozadavky/03 Read pozadavek simple.py new file mode 100644 index 0000000..8ef1208 --- /dev/null +++ b/10ReadPozadavky/03 Read pozadavek simple.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json +from pathlib import Path +import requests + +# --- Settings ---------------------------------------------------- +TOKEN_PATH = Path("token.txt") # file contains ONLY the token, no "Bearer " +CLINIC_SLUG = "mudr-buzalkova" +# ----------------------------------------------------------------- + +GRAPHQL_QUERY = r""" +query ClinicLegacyRequestList_ListPatientRequestsForClinic( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $state: PatientRequestState, + $pageInfo: PageInfo!, + $locale: Locale! +) { + requests: listPatientRequestsForClinic( + clinicSlug: $clinicSlug, + queueId: $queueId, + queueAssignment: $queueAssignment, + state: $state, + pageInfo: $pageInfo + ) { + id + displayTitle(locale: $locale) + extendedPatient { + name + surname + identificationNumber + } + } +} +""" + +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +def main(): + token = read_token(TOKEN_PATH) + + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + variables = { + "clinicSlug": CLINIC_SLUG, + "queueId": None, + "queueAssignment": "ANY", + "state": "ACTIVE", # pending / nevyřízené + "pageInfo": {"first": 30, "offset": 0}, + "locale": "cs", + } + + payload = { + "operationName": "ClinicLegacyRequestList_ListPatientRequestsForClinic", + "query": GRAPHQL_QUERY, + "variables": variables, + } + + url = "https://api.medevio.cz/graphql" + print("📡 Querying Medevio GraphQL API...\n") + r = requests.post(url, json=payload, headers=headers) + print(f"HTTP status: {r.status_code}\n") + + # --- Parse JSON safely + try: + data = r.json() + except Exception as e: + print("❌ Failed to decode JSON:", e) + print("Raw text:\n", r.text) + return + + requests_data = data.get("data", {}).get("requests", []) + if not requests_data: + print("⚠️ No requests found or invalid response.") + return + + print(f"📋 Found {len(requests_data)} active requests:\n") + for req in requests_data: + patient = req.get("extendedPatient", {}) + print(f"- {patient.get('surname','')} {patient.get('name','')} " + f"({patient.get('identificationNumber','')}) " + f"→ {req.get('displayTitle','')} [ID: {req.get('id')}]") + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/04 Dalsi.py b/10ReadPozadavky/04 Dalsi.py new file mode 100644 index 0000000..f5960f6 --- /dev/null +++ b/10ReadPozadavky/04 Dalsi.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json +from pathlib import Path +import requests + +TOKEN_PATH = Path("token.txt") +CLINIC_SLUG = "mudr-buzalkova" + +# --- Try including `updatedAt` field directly --- +GRAPHQL_QUERY = r""" +query ClinicRequestGrid_ListPatientRequestsForClinic2( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $pageInfo: PageInfo!, + $locale: Locale! +) { + requestsResponse: listPatientRequestsForClinic2( + clinicSlug: $clinicSlug, + queueId: $queueId, + queueAssignment: $queueAssignment, + pageInfo: $pageInfo + ) { + count + patientRequests { + id + createdAt + updatedAt # 👈 TESTUJEME, jestli Medevio toto pole podporuje + doneAt + removedAt + displayTitle(locale: $locale) + lastMessage { createdAt } + extendedPatient { + name + surname + identificationNumber + } + } + } +} +""" + +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + + +def main(): + token = read_token(TOKEN_PATH) + + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + variables = { + "clinicSlug": CLINIC_SLUG, + "queueId": None, + "queueAssignment": "ANY", + "pageInfo": {"first": 3, "offset": 0}, + "locale": "cs", + } + + payload = { + "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2", + "query": GRAPHQL_QUERY, + "variables": variables, + } + + url = "https://api.medevio.cz/graphql" + print("📡 Querying Medevio GraphQL API (testing `updatedAt` field)...\n") + + r = requests.post(url, json=payload, headers=headers) + print(f"HTTP status: {r.status_code}\n") + + try: + data = r.json() + except Exception as e: + print("❌ Failed to parse JSON:", e) + print("Raw text:\n", r.text) + return + + print("=== JSON response ===") + print(json.dumps(data, indent=2, ensure_ascii=False)) + + # Quick check: did it return an error message about updatedAt? + errors = data.get("errors") + if errors: + print("\n⚠️ Medevio returned GraphQL error:") + for e in errors: + print(f" → {e.get('message')}") + else: + print("\n✅ No errors, `updatedAt` might exist in schema!") + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/05 Další.py b/10ReadPozadavky/05 Další.py new file mode 100644 index 0000000..3f6d009 --- /dev/null +++ b/10ReadPozadavky/05 Další.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json +from pathlib import Path +import requests + +TOKEN_PATH = Path("token.txt") +CLINIC_SLUG = "mudr-buzalkova" + +GRAPHQL_QUERY = r""" +query ClinicRequestGrid_ListPatientRequestsForClinic2( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $pageInfo: PageInfo!, + $locale: Locale! +) { + requestsResponse: listPatientRequestsForClinic2( + clinicSlug: $clinicSlug + queueId: $queueId + queueAssignment: $queueAssignment + pageInfo: $pageInfo + ) { + count + patientRequests { + id + createdAt + doneAt + displayTitle(locale: $locale) + extendedPatient { + name + surname + identificationNumber + } + } + } +} +""" + +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +def main(): + token = read_token(TOKEN_PATH) + + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + # 👇 state zcela vynechán + variables = { + "clinicSlug": CLINIC_SLUG, + "queueId": None, + "queueAssignment": "ANY", + "pageInfo": {"first": 10, "offset": 0}, + "locale": "cs", + } + + payload = { + "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2", + "query": GRAPHQL_QUERY, + "variables": variables, + } + + url = "https://api.medevio.cz/graphql" + print("📡 Querying Medevio GraphQL API (no state argument)...\n") + r = requests.post(url, json=payload, headers=headers) + print(f"HTTP status: {r.status_code}\n") + + try: + data = r.json() + print("=== JSON response ===") + print(json.dumps(data, indent=2, ensure_ascii=False)) + except Exception as e: + print("❌ Failed to parse JSON:", e) + print("Raw text:\n", r.text) + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/06 Načti všechny požadavky do mySQL.py b/10ReadPozadavky/06 Načti všechny požadavky do mySQL.py new file mode 100644 index 0000000..f268adb --- /dev/null +++ b/10ReadPozadavky/06 Načti všechny požadavky do mySQL.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json +import time +import pymysql +import requests +from pathlib import Path +from datetime import datetime + +# ================================ +# 🔧 CONFIGURATION +# ================================ +TOKEN_PATH = Path("token.txt") +CLINIC_SLUG = "mudr-buzalkova" +BATCH_SIZE = 100 +STATES = ["ACTIVE", "DONE"] # optionally add "REMOVED" + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3307, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +GRAPHQL_QUERY = r""" +query ClinicRequestGrid_ListPatientRequestsForClinic2( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $pageInfo: PageInfo!, + $locale: Locale!, + $state: PatientRequestState +) { + requestsResponse: listPatientRequestsForClinic2( + clinicSlug: $clinicSlug, + queueId: $queueId, + queueAssignment: $queueAssignment, + pageInfo: $pageInfo, + state: $state + ) { + count + patientRequests { + id + displayTitle(locale: $locale) + createdAt + updatedAt + doneAt + removedAt + extendedPatient { + name + surname + identificationNumber + } + } + } +} +""" + +# ================================ +# 🔑 TOKEN +# ================================ +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +# ================================ +# 🕒 DATETIME CONVERSION +# ================================ +def to_mysql_dt(iso_str): + """Convert ISO 8601 (with Z) to MySQL DATETIME.""" + if not iso_str: + return None + try: + dt = datetime.fromisoformat(iso_str.replace("Z", "+00:00")) + return dt.strftime("%Y-%m-%d %H:%M:%S") + except Exception: + return None + +# ================================ +# 💾 UPSERT TO MYSQL +# ================================ +def upsert(conn, r): + p = (r.get("extendedPatient") or {}) + 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")), + to_mysql_dt(r.get("updatedAt")), + 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 ONE BATCH +# ================================ +def fetch_batch(headers, state, offset): + variables = { + "clinicSlug": CLINIC_SLUG, + "queueId": None, + "queueAssignment": "ANY", + "pageInfo": {"first": BATCH_SIZE, "offset": offset}, + "locale": "cs", + "state": state, + } + payload = { + "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2", + "query": GRAPHQL_QUERY, + "variables": variables, + } + r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers) + r.raise_for_status() + data = r.json().get("data", {}).get("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) + + total_downloaded = 0 + total_upserted = 0 + + for state in STATES: + print(f"\n📡 STATE = {state}") + offset = 0 + state_total = None + while True: + batch, count_total = fetch_batch(headers, state, offset) + if state_total is None: + state_total = count_total + print(f" • Total from server: {state_total}") + if not batch: + break + print(f" • Offset {offset:>5}: got {len(batch)}") + for r in batch: + upsert(conn, r) + total_upserted += 1 + total_downloaded += len(batch) + offset += BATCH_SIZE + if offset >= state_total: + break + time.sleep(0.4) # respect API + + conn.close() + print(f"\n✅ Done. Downloaded {total_downloaded} items, upserted {total_upserted} rows (states: {', '.join(STATES)}).") + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/0601.py b/10ReadPozadavky/0601.py new file mode 100644 index 0000000..e614f92 --- /dev/null +++ b/10ReadPozadavky/0601.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json +import time +import pymysql +import requests +from pathlib import Path +from datetime import datetime + +# ================================ +# 🔧 CONFIGURATION +# ================================ +TOKEN_PATH = Path("token.txt") +CLINIC_SLUG = "mudr-buzalkova" +BATCH_SIZE = 100 +STATES = ["ACTIVE", "DONE"] # optionally add "REMOVED" + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3307, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +GRAPHQL_QUERY = r""" +query ClinicRequestGrid_ListPatientRequestsForClinic2( + $clinicSlug: String!, + $queueId: String, + $queueAssignment: QueueAssignmentFilter!, + $pageInfo: PageInfo!, + $locale: Locale!, + $state: PatientRequestState +) { + requestsResponse: listPatientRequestsForClinic2( + clinicSlug: $clinicSlug, + queueId: $queueId, + queueAssignment: $queueAssignment, + pageInfo: $pageInfo, + state: $state + ) { + count + patientRequests { + id + displayTitle(locale: $locale) + createdAt + updatedAt + doneAt + removedAt + extendedPatient { + name + surname + identificationNumber + } + } + } +} +""" + +# ================================ +# 🔑 TOKEN +# ================================ +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +# ================================ +# 🕒 DATETIME CONVERSION +# ================================ +def to_mysql_dt(iso_str): + """Convert ISO 8601 (with Z) to MySQL DATETIME.""" + if not iso_str: + return None + try: + dt = datetime.fromisoformat(iso_str.replace("Z", "+00:00")) + return dt.strftime("%Y-%m-%d %H:%M:%S") + except Exception: + return None + + + + +# ================================ +# 💾 UPSERT TO MYSQL +# ================================ +def upsert_many(conn, batch): + """Upsert multiple records in one commit.""" + if not batch: + return + 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 = [] + for r in batch: + p = (r.get("extendedPatient") or {}) + vals.append(( + r.get("id"), + r.get("displayTitle"), + to_mysql_dt(r.get("createdAt")), + to_mysql_dt(r.get("updatedAt")), + 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.executemany(sql, vals) + conn.commit() + +def upsert(conn, r): + p = (r.get("extendedPatient") or {}) + 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")), + to_mysql_dt(r.get("updatedAt")), + 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 ONE BATCH +# ================================ +def fetch_batch(headers, state, offset): + variables = { + "clinicSlug": CLINIC_SLUG, + "queueId": None, + "queueAssignment": "ANY", + "pageInfo": {"first": BATCH_SIZE, "offset": offset}, + "locale": "cs", + "state": state, + } + payload = { + "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2", + "query": GRAPHQL_QUERY, + "variables": variables, + } + r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers) + r.raise_for_status() + data = r.json().get("data", {}).get("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) + + total_downloaded = 0 + total_upserted = 0 + + for state in STATES: + print(f"\n📡 STATE = {state}") + offset = 0 + state_total = None + while True: + batch, count_total = fetch_batch(headers, state, offset) + if state_total is None: + state_total = count_total + print(f" • Total from server: {state_total}") + if not batch: + break + print(f" • Offset {offset:>5}: got {len(batch)}") + for r in batch: + # upsert(conn, r) + upsert_many(conn, batch) + total_upserted += 1 + total_downloaded += len(batch) + offset += BATCH_SIZE + if offset >= state_total: + break + time.sleep(0.4) # respect API + + conn.close() + print(f"\n✅ Done. Downloaded {total_downloaded} items, upserted {total_upserted} rows (states: {', '.join(STATES)}).") + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/07 Ulož přílohy požadavku do filesystem.py b/10ReadPozadavky/07 Ulož přílohy požadavku do filesystem.py new file mode 100644 index 0000000..d67e43f --- /dev/null +++ b/10ReadPozadavky/07 Ulož přílohy požadavku do filesystem.py @@ -0,0 +1,92 @@ +import requests +import json +from pathlib import Path + +# === Nastavení === +TOKEN_PATH = Path("token.txt") +REQUEST_ID = "092a0c63-28be-4c6b-ab3b-204e1e2641d4" +OUTPUT_DIR = Path(r"u:\Dropbox\!!!Days\Downloads Z230\Medevio_přílohy") + +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +GRAPHQL_QUERY = r""" +query ClinicRequestDetail_GetPatientRequest2( + $requestId: UUID!, + $isDoctor: Boolean! +) { + patientRequestMedicalRecords: listMedicalRecordsForPatientRequest( + attachmentTypes: [ECRF_FILL_ATTACHMENT, MESSAGE_ATTACHMENT, PATIENT_REQUEST_ATTACHMENT] + patientRequestId: $requestId + pageInfo: {first: 100, offset: 0} + ) { + attachmentType + id + medicalRecord { + contentType + description + downloadUrl + id + url + visibleToPatient @include(if: $isDoctor) + } + } +} +""" + +variables = { + "isDoctor": True, + "requestId": REQUEST_ID, +} + +headers = { + "Authorization": f"Bearer {read_token(TOKEN_PATH)}", + "Content-Type": "application/json", + "Accept": "application/json", +} + +payload = { + "operationName": "ClinicRequestDetail_GetPatientRequest2", + "query": GRAPHQL_QUERY, + "variables": variables, +} + +print("📡 Querying Medevio API for attachments...\n") +r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers) +print(f"HTTP status: {r.status_code}\n") + +data = r.json() +records = data.get("data", {}).get("patientRequestMedicalRecords", []) +if not records: + print("⚠️ No attachments found.") + exit() + +# === Uložení === +OUTPUT_DIR.mkdir(parents=True, exist_ok=True) +print(f"📂 Saving {len(records)} attachments to: {OUTPUT_DIR}\n") + +for rec in records: + med = rec.get("medicalRecord", {}) + url = med.get("downloadUrl") + name = med.get("description", med.get("id")) or "unknown.pdf" + + if not url: + print(f"❌ Skipped {name} (no download URL)") + continue + + safe_name = name.replace("/", "_").replace("\\", "_") + out_path = OUTPUT_DIR / safe_name + + print(f"⬇️ Downloading: {safe_name}") + try: + file_data = requests.get(url, timeout=30) + file_data.raise_for_status() + out_path.write_bytes(file_data.content) + print(f"✅ Saved: {out_path.name} ({len(file_data.content)/1024:.1f} KB)") + except Exception as e: + print(f"❌ Error saving {safe_name}: {e}") + +print("\n🎉 Done!") diff --git a/10ReadPozadavky/0701 test.py b/10ReadPozadavky/0701 test.py new file mode 100644 index 0000000..407435c --- /dev/null +++ b/10ReadPozadavky/0701 test.py @@ -0,0 +1,58 @@ +import requests +import json +from pathlib import Path + +TOKEN_PATH = Path("token.txt") +REQUEST_ID = "092a0c63-28be-4c6b-ab3b-204e1e2641d4" + +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +GRAPHQL_QUERY = r""" +query ClinicRequestDetail_GetPatientRequest2( + $requestId: UUID!, + $isDoctor: Boolean! +) { + patientRequestMedicalRecords: listMedicalRecordsForPatientRequest( + attachmentTypes: [ECRF_FILL_ATTACHMENT, MESSAGE_ATTACHMENT, PATIENT_REQUEST_ATTACHMENT] + patientRequestId: $requestId + pageInfo: {first: 100, offset: 0} + ) { + attachmentType + id + medicalRecord { + contentType + description + downloadUrl + id + url + visibleToPatient @include(if: $isDoctor) + } + } +} +""" + +variables = { + "isDoctor": True, + "requestId": REQUEST_ID, +} + +headers = { + "Authorization": f"Bearer {read_token(TOKEN_PATH)}", + "Content-Type": "application/json", + "Accept": "application/json", +} + +payload = { + "operationName": "ClinicRequestDetail_GetPatientRequest2", + "query": GRAPHQL_QUERY, + "variables": variables, +} + +print("📡 Querying Medevio API...\n") +r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers) +print(f"HTTP status: {r.status_code}\n") +print(json.dumps(r.json(), indent=2, ensure_ascii=False)) diff --git a/10ReadPozadavky/0702 test.py b/10ReadPozadavky/0702 test.py new file mode 100644 index 0000000..b351002 --- /dev/null +++ b/10ReadPozadavky/0702 test.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import json +import requests +import pymysql +from pathlib import Path +from datetime import datetime + +# ============================== +# 🔧 CONFIGURATION +# ============================== +TOKEN_PATH = Path("token.txt") +CLINIC_SLUG = "mudr-buzalkova" +BASE_DIR = Path(r"u:\Dropbox\!!!Days\Downloads Z230\Medevio_přílohy") +BASE_DIR.mkdir(parents=True, exist_ok=True) + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3307, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +GRAPHQL_QUERY = r""" +query ClinicRequestDetail_GetPatientRequest2( + $requestId: UUID!, + $clinicSlug: String!, + $isDoctor: Boolean!, + $locale: Locale! +) { + patientRequestMedicalRecords: listMedicalRecordsForPatientRequest( + attachmentTypes: [ECRF_FILL_ATTACHMENT, MESSAGE_ATTACHMENT, PATIENT_REQUEST_ATTACHMENT] + patientRequestId: $requestId + pageInfo: {first: 100, offset: 0} + ) { + attachmentType + id + medicalRecord { + contentType + description + downloadUrl + id + url + visibleToPatient + } + } +} +""" + +# ============================== +# 🔑 TOKEN +# ============================== +def read_token(p: Path) -> str: + tok = p.read_text(encoding="utf-8").strip() + if tok.startswith("Bearer "): + tok = tok.split(" ", 1)[1] + return tok + +# ============================== +# 💾 DOWNLOAD FILE +# ============================== +def download_file(url: str, out_path: Path): + try: + r = requests.get(url, timeout=30) + r.raise_for_status() + out_path.parent.mkdir(parents=True, exist_ok=True) + with open(out_path, "wb") as f: + f.write(r.content) + print(f" 💾 Saved: {out_path.relative_to(BASE_DIR)}") + except Exception as e: + print(f" ⚠️ Failed to download {out_path.name}: {e}") + +# ============================== +# 📡 FETCH ATTACHMENTS +# ============================== +def fetch_attachments(headers, request_id): + variables = { + "requestId": request_id, + "clinicSlug": CLINIC_SLUG, + "isDoctor": True, + "locale": "cs", + } + payload = { + "operationName": "ClinicRequestDetail_GetPatientRequest2", + "query": GRAPHQL_QUERY, + "variables": variables, + } + r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers) + if r.status_code != 200: + print(f"❌ HTTP {r.status_code}") + return [] + data = r.json().get("data", {}).get("patientRequestMedicalRecords", []) + return data + +# ============================== +# 🧠 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) + with conn.cursor() as cur: + cur.execute(""" + SELECT id, displayTitle, pacient_prijmeni, pacient_jmeno, createdAt + FROM pozadavky + WHERE displayTitle = 'Odeslat lékařskou zprávu' + """) + rows = cur.fetchall() + + print(f"📋 Found {len(rows)} 'Odeslat lékařskou zprávu' requests") + + for i, row in enumerate(rows, 1): + req_id = row["id"] + prijmeni = row.get("pacient_prijmeni") or "Neznamy" + jmeno = row.get("pacient_jmeno") or "" + created = row.get("createdAt") + created_date = None + if created: + try: + created_date = datetime.strptime(str(created), "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%d") + except Exception: + created_date = "unknown" + + patient_dir = BASE_DIR / f"{prijmeni}, {jmeno}" / created_date + print(f"\n[{i}/{len(rows)}] 📂 {patient_dir.relative_to(BASE_DIR)}") + + attachments = fetch_attachments(headers, req_id) + if not attachments: + print(" ⚠️ No attachments") + continue + + for a in attachments: + m = a.get("medicalRecord") or {} + fname = m.get("description") or f"{m.get('id')}.bin" + url = m.get("downloadUrl") + if url: + out_path = patient_dir / fname + download_file(url, out_path) + + conn.close() + print("\n✅ Done!") + +if __name__ == "__main__": + main() diff --git a/10ReadPozadavky/token.txt b/10ReadPozadavky/token.txt new file mode 100644 index 0000000..d31188b --- /dev/null +++ b/10ReadPozadavky/token.txt @@ -0,0 +1 @@ +nYvrvgflIKcDiQg8Hhpud+qG8iGZ8eH8su4nyT/Mgcm7XQp65ygY9s39+O01wIpk/7sKd6fBHkiKvsqH \ No newline at end of file