diff --git a/.idea/Medevio.iml b/.idea/Medevio.iml
index b6731d8..3cd7809 100644
--- a/.idea/Medevio.iml
+++ b/.idea/Medevio.iml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 912bb5e..7a3c570 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/Testy/000 Testy.py b/Testy/000 Testy.py
deleted file mode 100644
index 1114bf5..0000000
--- a/Testy/000 Testy.py
+++ /dev/null
@@ -1,229 +0,0 @@
-import os
-import shutil
-import pymysql
-import re
-from pathlib import Path
-from datetime import datetime
-import time
-
-# ==============================
-# ⚙️ CONFIGURATION
-# ==============================
-DB_CONFIG = {
- "host": "127.0.0.1",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
-}
-
-BASE_DIR = Path(r"z:\Dropbox\Ordinace\Dokumentace_ke_zpracování\MP")
-BASE_DIR.mkdir(parents=True, exist_ok=True)
-
-
-# ---- helper function for timing ----
-def log_section(name):
- print(f"\n=== ⏱ {name} ===")
- return time.time()
-
-
-def log_done(start):
- print(f" -> done in {time.time() - start:0.2f} sec")
-
-
-def sanitize_name(name: str) -> str:
- return re.sub(r'[<>:"/\\|?*\x00-\x1F]', "_", name).strip()
-
-
-def make_abbrev(title: str) -> str:
- if not title:
- return ""
- words = re.findall(r"[A-Za-zÁ-Žá-ž0-9]+", title)
- abbr = "".join(w if w.isdigit() else w[0] for w in words)
- return abbr.upper()
-
-
-# ==============================
-# 🧹 DELETE UNEXPECTED FILES
-# ==============================
-def clean_folder(folder: Path, valid_files: set):
- start = log_section(f"Cleaning folder: {folder.name}")
- if not folder.exists():
- log_done(start)
- return
-
- for f in folder.iterdir():
- if f.is_file():
-
- if f.name.startswith("▲"):
- continue
-
- sanitized = sanitize_name(f.name)
- if sanitized not in valid_files:
- print(f"🗑 Removing unexpected: {f.name}")
- try:
- f.unlink()
- except Exception as e:
- print(f"⚠ Could not delete {f}: {e}")
-
- log_done(start)
-
-
-# ==============================
-# 📦 DB CONNECTION
-# ==============================
-print("\n🔌 Connecting to DB…")
-start_db = time.time()
-conn = pymysql.connect(**DB_CONFIG)
-cur_meta = conn.cursor(pymysql.cursors.DictCursor)
-cur_blob = conn.cursor()
-print(f" -> connected in {time.time() - start_db:0.2f} sec")
-
-print("\n🔍 Loading metadata from DB…")
-start_sql = time.time()
-
-cur_meta.execute("""
- SELECT d.id AS download_id,
- d.request_id,
- d.filename,
- d.created_at,
- p.updatedAt AS req_updated_at,
- p.pacient_jmeno AS jmeno,
- p.pacient_prijmeni AS prijmeni,
- p.displayTitle
- FROM medevio_downloads d
- JOIN pozadavky p ON d.request_id = p.id
- ORDER BY p.updatedAt DESC
-""")
-
-rows = cur_meta.fetchall()
-
-print(f"📋 Loaded {len(rows)} attachment rows in {time.time() - start_sql:0.2f} sec.\n")
-
-
-# ==============================
-# 🧠 MAIN LOOP
-# ==============================
-processed_requests = set()
-
-for r in rows:
- req_id = r["request_id"]
-
- if req_id in processed_requests:
- continue
- processed_requests.add(req_id)
-
- section = f"Processing request {req_id}"
- sec_start = log_section(section)
-
- # ========== FETCH ALL VALID FILES ==========
- start_valid = log_section("Loading valid filenames")
- cur_meta.execute(
- "SELECT filename FROM medevio_downloads WHERE request_id=%s",
- (req_id,)
- )
- valid_files = {sanitize_name(row["filename"]) for row in cur_meta.fetchall()}
- log_done(start_valid)
-
- # ========== PREPARE FOLDER NAME ==========
- updated_at = r["req_updated_at"] or datetime.now()
- date_str = updated_at.strftime("%Y-%m-%d")
-
- prijmeni = sanitize_name(r["prijmeni"] or "Unknown")
- jmeno = sanitize_name(r["jmeno"] or "")
- title = r.get("displayTitle") or ""
- abbr = make_abbrev(title)
-
- clean_folder_name = sanitize_name(
- f"{date_str} {prijmeni}, {jmeno} [{abbr}] {req_id}"
- )
-
- # ========== DETECT EXISTING FOLDER ==========
- start_detect = log_section("Detecting existing folder(s)")
- existing_folder = None
- folder_has_flag = False
-
- for f in BASE_DIR.iterdir():
- if f.is_dir() and req_id in f.name:
- existing_folder = f
- folder_has_flag = ("▲" in f.name)
- break
- log_done(start_detect)
-
- main_folder = existing_folder if existing_folder else BASE_DIR / clean_folder_name
-
- # ========== MERGE DUPLICATES ==========
- start_merge = log_section("Scanning for duplicate folders")
- possible_dups = [
- f for f in BASE_DIR.iterdir()
- if f.is_dir() and req_id in f.name and f != main_folder
- ]
-
- for dup in possible_dups:
- print(f"♻ Merging duplicate folder: {dup.name}")
- clean_folder(dup, valid_files)
- main_folder.mkdir(parents=True, exist_ok=True)
-
- for f in dup.iterdir():
- if f.is_file():
- target = main_folder / f.name
- if not target.exists():
- f.rename(target)
- shutil.rmtree(dup, ignore_errors=True)
-
- log_done(start_merge)
-
- # ========== CLEAN MAIN FOLDER ==========
- clean_folder(main_folder, valid_files)
-
- # ========== DOWNLOAD MISSING FILES ==========
- start_dl = log_section("Downloading missing files")
- added_new_file = False
- main_folder.mkdir(parents=True, exist_ok=True)
-
- for filename in valid_files:
- dest_plain = main_folder / filename
- dest_marked = main_folder / ("▲" + filename)
-
- if dest_plain.exists() or dest_marked.exists():
- continue
-
- added_new_file = True
-
- cur_blob.execute(
- "SELECT file_content FROM medevio_downloads "
- "WHERE request_id=%s AND filename=%s",
- (req_id, filename)
- )
- row = cur_blob.fetchone()
-
- if not row or not row[0]:
- continue
-
- with open(dest_plain, "wb") as f:
- f.write(row[0])
-
- print(f"💾 wrote: {dest_plain.name}")
-
- log_done(start_dl)
-
- # ========== REMOVE FOLDER FLAG ==========
- if added_new_file and "▲" in main_folder.name:
- try:
- new_name = main_folder.name.replace("▲", "").strip()
- new_path = main_folder.parent / new_name
- main_folder.rename(new_path)
- print(f"🔄 Folder flag removed → {new_name}")
- main_folder = new_path
- except Exception as e:
- print(f"⚠ Could not rename folder: {e}")
-
- log_done(sec_start)
-
-
-print("\n🎯 Export complete.\n")
-
-cur_blob.close()
-cur_meta.close()
-conn.close()
diff --git a/Testy/17 test.py b/Testy/01 Test
similarity index 92%
rename from Testy/17 test.py
rename to Testy/01 Test
index 2b05def..9da1805 100644
--- a/Testy/17 test.py
+++ b/Testy/01 Test
@@ -96,7 +96,18 @@ def fetch_messages(headers, request_id):
if r.status_code != 200:
print("❌ HTTP", r.status_code, "for request", request_id)
return []
- return r.json().get("data", {}).get("messages", []) or []
+
+ try:
+ data = r.json()
+ except Exception as e:
+ print(f"❌ Failed to parse JSON for {request_id}: {e}")
+ print(" Response text:", r.text[:500])
+ return []
+
+ messages = data.get("data", {}).get("messages", []) or []
+ print(f" 🌐 API returned {len(messages)} messages for {request_id}")
+ return messages
+
# ==============================
@@ -218,18 +229,19 @@ def main():
print(f"📦 Already downloaded attachments: {len(existing_ids)}\n")
- # ---- Select pozadavky needing message sync
+ # ---- Select 10 oldest pozadavky (regardless of messagesProcessed)
sql = """
SELECT id
FROM pozadavky
- WHERE messagesProcessed IS NULL
- OR messagesProcessed < updatedAt
+ ORDER BY updatedAt ASC
+ LIMIT 10
"""
with conn.cursor() as cur:
cur.execute(sql)
requests_to_process = cur.fetchall()
- print(f"📋 Found {len(requests_to_process)} pozadavků requiring message sync.\n")
+ print(f"📋 Will process {len(requests_to_process)} oldest pozadavků.\n")
+
# ---- Process each pozadavek
for idx, row in enumerate(requests_to_process, 1):
diff --git a/Testy/01 Test.py b/Testy/01 Test.py
deleted file mode 100644
index cd421ff..0000000
--- a/Testy/01 Test.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-"""
-Test: Read conversation messages for one request_id and save full JSON.
-Uses same logic as the production messages downloader.
-"""
-
-import json
-import requests
-from pathlib import Path
-from datetime import datetime
-
-# ==============================
-# ⚙️ CONFIGURATION
-# ==============================
-TOKEN_PATH = Path("token.txt") # same token file as your working script
-REQUEST_ID = "092a0c63-28be-4c6b-ab3b-204e1e2641d4" # 🧾 replace as needed
-OUTPUT_DIR = Path(r"u:\Dropbox\!!!Days\Downloads Z230") # where to save the JSON
-
-GRAPHQL_QUERY = r"""
-query UseMessages_ListMessages($requestId: String!, $updatedSince: DateTime) {
- messages: listMessages(patientRequestId: $requestId, updatedSince: $updatedSince) {
- id
- createdAt
- updatedAt
- readAt
- text
- type
- sender {
- id
- name
- surname
- clinicId
- }
- medicalRecord {
- id
- description
- contentType
- url
- downloadUrl
- token
- createdAt
- updatedAt
- }
- }
-}
-"""
-
-# ==============================
-# 🔑 READ 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
-
-
-# ==============================
-# 🚀 FETCH FROM API
-# ==============================
-def fetch_messages(headers, request_id):
- variables = {"requestId": request_id, "updatedSince": None}
- payload = {
- "operationName": "UseMessages_ListMessages",
- "query": GRAPHQL_QUERY,
- "variables": variables,
- }
-
- r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
- print("HTTP status:", r.status_code)
- if r.status_code != 200:
- print("❌ Response preview:", r.text[:500])
- return None
- return r.json()
-
-
-# ==============================
-# 🧠 MAIN
-# ==============================
-def main():
- token = read_token(TOKEN_PATH)
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- data = fetch_messages(headers, REQUEST_ID)
- if not data:
- print("⚠️ No data returned.")
- return
-
- # Save full JSON to file
- OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
- output_path = OUTPUT_DIR / f"messages_{REQUEST_ID}.json"
- output_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
-
- print(f"✅ JSON saved to {output_path}")
-
- # Optional: print summary
- messages = data.get("data", {}).get("messages", [])
- print(f"💬 {len(messages)} messages found:")
- print("─" * 100)
-
- for msg in messages:
- sender = msg.get("sender") or {}
- sender_name = " ".join(x for x in [sender.get("name"), sender.get("surname")] if x).strip() or "(unknown)"
- text = (msg.get("text") or "").strip().replace("\n", " ")
- created = msg.get("createdAt", "")[:16].replace("T", " ")
- print(f"[{created}] {sender_name}: {text}")
- if msg.get("medicalRecord"):
- mr = msg["medicalRecord"]
- print(f" 📎 {mr.get('description') or '(no description)'} ({mr.get('contentType')})")
- print(f" URL: {mr.get('downloadUrl') or mr.get('url')}")
- print("─" * 100)
-
-
-# ==============================
-if __name__ == "__main__":
- main()
diff --git a/Testy/02 Test.py b/Testy/02 Test.py
deleted file mode 100644
index c9266df..0000000
--- a/Testy/02 Test.py
+++ /dev/null
@@ -1,296 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-"""
-Read conversation messages for pozadavky where messagesProcessed IS NULL
-(Optionally filtered by createdAt), insert them into `medevio_conversation`,
-and if a message has an attachment (medicalRecord), download it and save into
-`medevio_downloads` (same logic as your attachments script).
-Finally, mark pozadavky.messagesProcessed = NOW().
-"""
-
-import zlib
-import json
-import requests
-import pymysql
-from pathlib import Path
-from datetime import datetime
-import time
-
-# ==============================
-# 🔧 CONFIGURATION
-# ==============================
-TOKEN_PATH = Path("token.txt")
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-# ✅ Optional: Only process requests created after this date ("" = no limit)
-CREATED_AFTER = "2024-12-01"
-
-GRAPHQL_QUERY_MESSAGES = r"""
-query UseMessages_ListMessages($requestId: String!, $updatedSince: DateTime) {
- messages: listMessages(patientRequestId: $requestId, updatedSince: $updatedSince) {
- id
- createdAt
- updatedAt
- readAt
- text
- type
- sender {
- id
- name
- surname
- clinicId
- }
- medicalRecord {
- id
- description
- contentType
- url
- downloadUrl
- token
- createdAt
- updatedAt
- }
- }
-}
-"""
-
-# ==============================
-# 🧮 HELPERS
-# ==============================
-def short_crc8(uuid_str: str) -> str:
- return f"{zlib.crc32(uuid_str.encode('utf-8')) & 0xffffffff:08x}"
-
-def extract_filename_from_url(url: str) -> str:
- try:
- return url.split("/")[-1].split("?")[0]
- except Exception:
- return "unknown_filename"
-
-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 parse_dt(s):
- if not s:
- return None
- # handle both "YYYY-mm-ddTHH:MM:SS" and "YYYY-mm-dd HH:MM:SS"
- s = s.replace("T", " ")
- fmts = ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M")
- for f in fmts:
- try:
- return datetime.strptime(s[:19], f)
- except Exception:
- pass
- return None
-
-# ==============================
-# 📡 FETCH MESSAGES
-# ==============================
-def fetch_messages(headers, request_id):
- variables = {"requestId": request_id, "updatedSince": None}
- payload = {
- "operationName": "UseMessages_ListMessages",
- "query": GRAPHQL_QUERY_MESSAGES,
- "variables": variables,
- }
- r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
- if r.status_code != 200:
- print(f"❌ HTTP {r.status_code} for messages of request {request_id}")
- return []
- data = r.json().get("data", {}).get("messages", [])
- return data or []
-
-# ==============================
-# 💾 SAVE: conversation row
-# ==============================
-def insert_message(cur, req_id, msg):
- sender = msg.get("sender") or {}
- sender_name = " ".join(x for x in [sender.get("name"), sender.get("surname")] if x).strip() or None
- sender_id = sender.get("id")
- sender_clinic_id = sender.get("clinicId")
-
- text = msg.get("text")
- created_at = parse_dt(msg.get("createdAt"))
- read_at = parse_dt(msg.get("readAt"))
- updated_at = parse_dt(msg.get("updatedAt"))
-
- mr = msg.get("medicalRecord") or {}
- attachment_url = mr.get("downloadUrl") or mr.get("url")
- attachment_description = mr.get("description")
- attachment_content_type = mr.get("contentType")
-
- sql = """
- INSERT INTO medevio_conversation (
- id, request_id, sender_name, sender_id, sender_clinic_id,
- text, created_at, read_at, updated_at,
- attachment_url, attachment_description, attachment_content_type
- ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
- ON DUPLICATE KEY UPDATE
- sender_name = VALUES(sender_name),
- sender_id = VALUES(sender_id),
- sender_clinic_id = VALUES(sender_clinic_id),
- text = VALUES(text),
- created_at = VALUES(created_at),
- read_at = VALUES(read_at),
- updated_at = VALUES(updated_at),
- attachment_url = VALUES(attachment_url),
- attachment_description = VALUES(attachment_description),
- attachment_content_type = VALUES(attachment_content_type)
- """
- cur.execute(sql, (
- msg.get("id"),
- req_id,
- sender_name,
- sender_id,
- sender_clinic_id,
- text,
- created_at,
- read_at,
- updated_at,
- attachment_url,
- attachment_description,
- attachment_content_type
- ))
-
-# ==============================
-# 💾 SAVE: download attachment (from message)
-# ==============================
-def insert_download_from_message(cur, req_id, msg, existing_ids):
- mr = msg.get("medicalRecord") or {}
- attachment_id = mr.get("id")
- if not attachment_id:
- return False
- if attachment_id in existing_ids:
- print(f" ⏭️ Skipping already downloaded message-attachment {attachment_id}")
- return False
-
- url = mr.get("downloadUrl") or mr.get("url")
- if not url:
- return False
-
- try:
- r = requests.get(url, timeout=30)
- r.raise_for_status()
- content = r.content
- except Exception as e:
- print(f" ⚠️ Failed to download message attachment {attachment_id}: {e}")
- return False
-
- filename = extract_filename_from_url(url)
- content_type = mr.get("contentType")
- file_size = len(content)
- created_date = parse_dt(msg.get("createdAt"))
-
- # We don't have patient names on the message level here; keep NULLs.
- cur.execute("""
- INSERT INTO medevio_downloads (
- request_id, attachment_id, attachment_type, filename,
- content_type, file_size, pacient_jmeno, pacient_prijmeni,
- created_at, file_content
- ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
- ON DUPLICATE KEY UPDATE
- file_content = VALUES(file_content),
- file_size = VALUES(file_size),
- downloaded_at = NOW()
- """, (
- req_id,
- attachment_id,
- "MESSAGE_ATTACHMENT",
- filename,
- content_type,
- file_size,
- None,
- None,
- created_date,
- content
- ))
- existing_ids.add(attachment_id)
- print(f" 💾 Saved msg attachment {filename} ({file_size/1024:.1f} kB)")
- return True
-
-# ==============================
-# 🧠 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)
-
- # Load existing download IDs to skip duplicates (same logic as your script)
- print("📦 Loading list of already downloaded attachments...")
- with conn.cursor() as cur:
- cur.execute("SELECT attachment_id FROM medevio_downloads")
- existing_ids = {row["attachment_id"] for row in cur.fetchall()}
- print(f"✅ Found {len(existing_ids)} attachments already saved.")
-
- # Pull pozadavky where messagesProcessed IS NULL (optionally by createdAt)
- sql = """
- SELECT id, displayTitle, pacient_prijmeni, pacient_jmeno, createdAt
- FROM pozadavky
- WHERE messagesProcessed IS NULL
- """
- params = []
- if CREATED_AFTER:
- sql += " AND createdAt >= %s"
- params.append(CREATED_AFTER)
-
- with conn.cursor() as cur:
- cur.execute(sql, params)
- rows = cur.fetchall()
-
- print(f"📋 Found {len(rows)} pozadavky to process (messagesProcessed IS NULL"
- + (f", created >= {CREATED_AFTER}" if CREATED_AFTER else "") + ")")
-
- for i, row in enumerate(rows, 1):
- req_id = row["id"]
- prijmeni = row.get("pacient_prijmeni") or "Neznamy"
- jmeno = row.get("pacient_jmeno") or ""
- print(f"\n[{i}/{len(rows)}] 💬 {prijmeni}, {jmeno} ({req_id})")
-
- messages = fetch_messages(headers, req_id)
- if not messages:
- print(" ⚠️ No messages found")
- with conn.cursor() as cur:
- cur.execute("UPDATE pozadavky SET messagesProcessed = NOW() WHERE id = %s", (req_id,))
- conn.commit()
- continue
-
- inserted = 0
- with conn.cursor() as cur:
- for msg in messages:
- insert_message(cur, req_id, msg)
- # also pull any message attachments into downloads table
- insert_download_from_message(cur, req_id, msg, existing_ids)
- inserted += 1
- conn.commit()
-
- # mark processed
- with conn.cursor() as cur:
- cur.execute("UPDATE pozadavky SET messagesProcessed = NOW() WHERE id = %s", (req_id,))
- conn.commit()
-
- print(f" ✅ {inserted} messages processed for {prijmeni}, {jmeno}")
- time.sleep(0.3) # polite API delay
-
- conn.close()
- print("\n✅ Done! All new conversations processed and pozadavky updated.")
-
-# ==============================
-if __name__ == "__main__":
- main()
diff --git a/Testy/03 Test.py b/Testy/03 Test.py
deleted file mode 100644
index 6f1996e..0000000
--- a/Testy/03 Test.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import os
-import zlib
-import pymysql
-import re
-from pathlib import Path
-from datetime import datetime
-
-# ==============================
-# ⚙️ CONFIGURATION
-# ==============================
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
-}
-
-BASE_DIR = Path(r"u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\MP1")
-BASE_DIR.mkdir(parents=True, exist_ok=True)
-
-
-def sanitize_name(name: str) -> str:
- """Replace invalid filename characters with underscore."""
- return re.sub(r'[<>:"/\\|?*\x00-\x1F]', "_", name).strip()
-
-
-# ==============================
-# 📦 STREAMING EXPORT WITH TRIANGLE CHECK
-# ==============================
-conn = pymysql.connect(**DB_CONFIG)
-cur_meta = conn.cursor(pymysql.cursors.DictCursor)
-cur_blob = conn.cursor()
-
-cur_meta.execute("""
- SELECT id, request_id, attachment_id, filename, pacient_jmeno,
- pacient_prijmeni, created_at, downloaded_at
- FROM medevio_downloads
- WHERE file_content IS NOT NULL;
-""")
-
-rows = cur_meta.fetchall()
-print(f"📋 Found {len(rows)} records to check/export")
-
-skipped, exported = 0, 0
-
-for r in rows:
- try:
- created = r["created_at"] or r["downloaded_at"] or datetime.now()
- date_str = created.strftime("%Y-%m-%d")
-
- prijmeni = sanitize_name(r["pacient_prijmeni"] or "Unknown")
- jmeno = sanitize_name(r["pacient_jmeno"] or "")
-
- # 🔥 NEW: use full request_id instead of CRC32
- full_req_id = sanitize_name(r["request_id"])
-
- # Base (non-triangle) and processed (triangle) folder variants
- base_folder = f"{date_str} {prijmeni}, {jmeno} {full_req_id}"
- tri_folder = f"{date_str}▲ {prijmeni}, {jmeno} {full_req_id}"
-
- base_folder = sanitize_name(base_folder)
- tri_folder = sanitize_name(tri_folder)
-
- base_path = BASE_DIR / base_folder
- tri_path = BASE_DIR / tri_folder
-
- filename = sanitize_name(r["filename"] or f"unknown_{r['id']}.bin")
- file_path_base = base_path / filename
- file_path_tri = tri_path / filename
-
- # 🟡 Skip if exists in either version
- if file_path_base.exists() or file_path_tri.exists():
- skipped += 1
- found_in = "▲" if file_path_tri.exists() else ""
- print(f"⏭️ Skipping existing{found_in}: {filename}")
- continue
-
- # Make sure base folder exists before saving
- base_path.mkdir(parents=True, exist_ok=True)
-
- # 2️⃣ Fetch blob
- cur_blob.execute("SELECT file_content FROM medevio_downloads WHERE id = %s", (r["id"],))
- blob = cur_blob.fetchone()[0]
-
- if blob:
- with open(file_path_base, "wb") as f:
- f.write(blob)
- exported += 1
- print(f"✅ Saved: {file_path_base.relative_to(BASE_DIR)}")
- else:
- print(f"⚠️ No content for id={r['id']}")
-
- except Exception as e:
- print(f"❌ Error for id={r['id']}: {e}")
-
-cur_blob.close()
-cur_meta.close()
-conn.close()
-
-print(f"\n🎯 Export complete — {exported} new files saved, {skipped} skipped.\n")
diff --git a/Testy/03 Testt.py b/Testy/03 Testt.py
deleted file mode 100644
index 78f0820..0000000
--- a/Testy/03 Testt.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from pathlib import Path
-
-# ============================
-# CONFIG
-# ============================
-TOKEN_PATH = Path("token.txt")
-
-# vlož libovolný existující request ID
-REQUEST_ID = "3fc9b28c-ada2-4d21-ab2d-fe60ad29fd8f"
-
-GRAPHQL_NOTES_QUERY = r"""
-query ClinicRequestNotes_Get($patientRequestId: String!) {
- notes: getClinicPatientRequestNotes(requestId: $patientRequestId) {
- id
- content
- createdAt
- updatedAt
- createdBy {
- id
- name
- surname
- }
- }
-}
-"""
-
-# ============================
-# 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
-
-# ============================
-# FETCH
-# ============================
-def fetch_notes(request_id, token):
- url = "https://api.medevio.cz/graphql"
-
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- variables = {"patientRequestId": request_id}
-
- payload = {
- "operationName": "ClinicRequestNotes_Get",
- "query": GRAPHQL_NOTES_QUERY,
- "variables": variables,
- }
-
- r = requests.post(url, json=payload, headers=headers)
- r.raise_for_status()
- return r.json()
-
-# ============================
-# MAIN
-# ============================
-def main():
- token = read_token(TOKEN_PATH)
-
- print(f"\n🔍 Fetching NOTES for request:\n ID = {REQUEST_ID}\n")
-
- data = fetch_notes(REQUEST_ID, token)
-
- print("📄 FULL RAW JSON:\n")
- print(json.dumps(data, indent=2, ensure_ascii=False))
-
- print("\n📝 Parsed notes:\n")
- notes = data.get("data", {}).get("notes") or []
- if not notes:
- print(" (no notes found)")
- return
-
- for n in notes:
- author = n.get("createdBy")
- print(f"--- Note {n.get('id')} ---")
- print(f"Created: {n.get('createdAt')}")
- print(f"Updated: {n.get('updatedAt')}")
- if author:
- print(f"Author: {author.get('name')} {author.get('surname')}")
- print("Content:")
- print(n.get("content"))
- print()
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/04 Test.py b/Testy/04 Test.py
deleted file mode 100644
index 1a7d578..0000000
--- a/Testy/04 Test.py
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-"""
-Download all attachments for pozadavky where attachmentsProcessed IS NULL
-and (optionally) createdAt is newer than a cutoff date.
-Store them in MySQL table `medevio_downloads`, and update pozadavky.attachmentsProcessed.
-"""
-
-import zlib
-import json
-import requests
-import pymysql
-from pathlib import Path
-from datetime import datetime
-import time
-
-# ==============================
-# 🔧 CONFIGURATION
-# ==============================
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-CREATED_AFTER = "2024-12-01" # optional filter
-
-GRAPHQL_QUERY = r"""
-query ClinicRequestDetail_GetPatientRequest2($requestId: UUID!) {
- 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
- }
- }
-}
-"""
-
-# ==============================
-# 🧮 HELPERS
-# ==============================
-def extract_filename_from_url(url: str) -> str:
- try:
- return url.split("/")[-1].split("?")[0]
- except:
- return "unknown_filename"
-
-def read_token(p: Path) -> str:
- tok = p.read_text(encoding="utf-8").strip()
- return tok.split(" ", 1)[1] if tok.startswith("Bearer ") else tok
-
-# ==============================
-# 📡 FETCH ATTACHMENTS
-# ==============================
-def fetch_attachments(headers, request_id):
- payload = {
- "operationName": "ClinicRequestDetail_GetPatientRequest2",
- "query": GRAPHQL_QUERY,
- "variables": {"requestId": request_id},
- }
- r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
- if r.status_code != 200:
- print(f"❌ HTTP {r.status_code} for request {request_id}")
- return []
- return r.json().get("data", {}).get("patientRequestMedicalRecords", [])
-
-
-# ==============================
-# 💾 SAVE TO MYSQL (clean version)
-# ==============================
-def insert_download(cur, req_id, a, m, created_date, existing_ids):
-
- attachment_id = a.get("id")
- if attachment_id in existing_ids:
- print(f" ⏭️ Already downloaded {attachment_id}")
- return False
-
- url = m.get("downloadUrl")
- if not url:
- print(" ⚠️ Missing download URL")
- return False
-
- filename = extract_filename_from_url(url)
-
- # Download file
- try:
- r = requests.get(url, timeout=30)
- r.raise_for_status()
- content = r.content
- except Exception as e:
- print(f" ⚠️ Download failed {url}: {e}")
- return False
-
- file_size = len(content)
- attachment_type = a.get("attachmentType")
- content_type = m.get("contentType")
-
- # 🚨 CLEAN INSERT — no patient_jmeno/no patient_prijmeni
- cur.execute("""
- INSERT INTO medevio_downloads (
- request_id, attachment_id, attachment_type,
- filename, content_type, file_size,
- created_at, file_content
- ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
- ON DUPLICATE KEY UPDATE
- file_content = VALUES(file_content),
- file_size = VALUES(file_size),
- downloaded_at = NOW()
- """, (
- req_id,
- attachment_id,
- attachment_type,
- filename,
- content_type,
- file_size,
- created_date,
- content,
- ))
-
- existing_ids.add(attachment_id)
- print(f" 💾 Saved {filename} ({file_size/1024:.1f} kB)")
- return True
-
-
-# ==============================
-# 🧠 MAIN
-# ==============================
-def main():
- token = read_token(TOKEN_PATH)
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- }
-
- conn = pymysql.connect(**DB_CONFIG)
-
- # Load existing IDs
- with conn.cursor() as cur:
- cur.execute("SELECT attachment_id FROM medevio_downloads")
- existing_ids = {row["attachment_id"] for row in cur.fetchall()}
- print(f"✅ {len(existing_ids)} attachments already saved.")
-
- # Build query for pozadavky
- sql = """
- SELECT id, pacient_prijmeni, pacient_jmeno, createdAt
- FROM pozadavky
- WHERE attachmentsProcessed IS NULL
- """
- params = []
- if CREATED_AFTER:
- sql += " AND createdAt >= %s"
- params.append(CREATED_AFTER)
-
- with conn.cursor() as cur:
- cur.execute(sql, params)
- req_rows = cur.fetchall()
-
- print(f"📋 Found {len(req_rows)} pozadavky to process.")
-
- # Process each pozadavek
- for i, row in enumerate(req_rows, 1):
- req_id = row["id"]
- prijmeni = row.get("pacient_prijmeni") or "Neznamy"
- jmeno = row.get("pacient_jmeno") or ""
- created_date = row.get("createdAt") or datetime.now()
-
- print(f"\n[{i}/{len(req_rows)}] 🧾 {prijmeni}, {jmeno} ({req_id})")
-
- attachments = fetch_attachments(headers, req_id)
-
- if not attachments:
- print(" ⚠️ No attachments found")
- with conn.cursor() as cur:
- cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (req_id,))
- conn.commit()
- continue
-
- with conn.cursor() as cur:
- for a in attachments:
- m = a.get("medicalRecord") or {}
- insert_download(cur, req_id, a, m, created_date, existing_ids)
- conn.commit()
-
- # Mark processed
- with conn.cursor() as cur:
- cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (req_id,))
- conn.commit()
-
- print(f" ✅ Done ({len(attachments)} attachments)")
-
- time.sleep(0.3)
-
- conn.close()
- print("\n🎯 All attachments processed.")
-
-# ==============================
-if __name__ == "__main__":
- main()
diff --git a/Testy/05 Testy.py b/Testy/05 Testy.py
deleted file mode 100644
index 284f7d0..0000000
--- a/Testy/05 Testy.py
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from pathlib import Path
-
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-
-GRAPHQL_URL = "https://api.medevio.cz/graphql" # ← správná URL
-
-# 👉 nastav offset zde
-OFFSET = 0 # 0 = první pacient, 1 = druhý, 100 = 101. pacient
-FIRST = 1 # načteme jen jednoho
-
-QUERY = """
-query PatientGridImpl_ListClinicPatients(
- $clinicSlug: String!,
- $filter: ListPatientFilter!,
- $pageInfo: PageInfo!,
- $sort: [ListPatientsSort!]
-) {
- patientsList: listPatients(
- clinicSlug: $clinicSlug
- filter: $filter
- pageInfo: $pageInfo
- sort: $sort
- ) {
- count
- patients {
- id
- identificationNumber
- insuranceCompanyObject {
- id
- shortName
- }
- lastReservation
- locale
- name
- nextReservation
- key
- phone
- sex
- status2
- surname
- type
- kind
- isInClinic
- isUnknownPatient
- user {
- id
- name
- surname
- phone
- registrationCompletedTime
- }
- owner {
- name
- surname
- }
- clinics {
- id
- name
- slug
- }
- tags(onlyImportant: false) {
- id
- name
- color
- icon
- }
- }
- }
-}
-"""
-
-variables = {
- "clinicSlug": CLINIC_SLUG,
- "filter": {},
- "pageInfo": {
- "first": FIRST,
- "offset": OFFSET
- },
- "sort": [
- {
- "field": "ReverseFullName",
- "sort": "ASC"
- }
- ]
-}
-
-token = Path("token.txt").read_text().strip()
-
-headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
-}
-
-print("⏳ Fetching patient...")
-response = requests.post(
- GRAPHQL_URL,
- json={"query": QUERY, "variables": variables},
- headers=headers
-)
-
-response.raise_for_status()
-data = response.json()
-
-print("\n📌 RAW JSON RESPONSE:\n")
-print(json.dumps(data, indent=2, ensure_ascii=False))
diff --git a/Testy/06 Testy.py b/Testy/06 Testy.py
deleted file mode 100644
index 289af46..0000000
--- a/Testy/06 Testy.py
+++ /dev/null
@@ -1,203 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-import pymysql
-from pathlib import Path
-
-# ==============================
-# 🔧 KONFIGURACE
-# ==============================
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-GRAPHQL_URL = "https://api.medevio.cz/graphql"
-
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-# počet pacientů na stránku
-PAGE_SIZE = 100
-
-
-# ==============================
-# 📌 GRAPHQL QUERY
-# ==============================
-QUERY = """
-query PatientGridImpl_ListClinicPatients(
- $clinicSlug: String!,
- $filter: ListPatientFilter!,
- $pageInfo: PageInfo!,
- $sort: [ListPatientsSort!]
-) {
- patientsList: listPatients(
- clinicSlug: $clinicSlug
- filter: $filter
- pageInfo: $pageInfo
- sort: $sort
- ) {
- count
- patients {
- id
- identificationNumber
- insuranceCompanyObject {
- id
- shortName
- }
- name
- surname
- phone
- sex
- status2
- type
- kind
- isInClinic
- isUnknownPatient
- user {
- registrationCompletedTime
- }
- clinics {
- id
- name
- slug
- }
- tags(onlyImportant: false) {
- id
- name
- color
- icon
- }
- }
- }
-}
-"""
-from datetime import datetime
-
-def normalize_dt(dt_str):
- if not dt_str:
- return None
- # remove Z
- dt_str = dt_str.replace("Z", "")
- # replace T with space
- dt_str = dt_str.replace("T", " ")
- # remove fractional seconds
- if "." in dt_str:
- dt_str = dt_str.split(".")[0]
- return dt_str # MySQL can accept "YYYY-MM-DD HH:MM:SS"
-
-# ==============================
-# 💾 ULOŽENÍ PACIENTA
-# ==============================
-def save_patient_summary(cur, p):
- sql = """
- REPLACE INTO medevio_pacienti (
- id, jmeno, prijmeni, rodne_cislo, telefon, pohlavi,
- pojistovna_id, pojistovna_nazev,
- status, typ, kind,
- is_in_clinic, is_unknown,
- registration_time,
- tags_json, clinics_json,
- last_update
- )
- VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,NOW())
- """
-
- ins = p.get("insuranceCompanyObject") or {}
- user = p.get("user") or {}
-
- cur.execute(sql, (
- p.get("id"),
- p.get("name"),
- p.get("surname"),
- p.get("identificationNumber"),
- p.get("phone"),
- p.get("sex"),
- ins.get("id"),
- ins.get("shortName"),
- p.get("status2"),
- p.get("type"),
- p.get("kind"),
- 1 if p.get("isInClinic") else 0,
- 1 if p.get("isUnknownPatient") else 0,
- normalize_dt(user.get("registrationCompletedTime")),
- json.dumps(p.get("tags"), ensure_ascii=False),
- json.dumps(p.get("clinics"), ensure_ascii=False),
- ))
-
-
-# ==============================
-# 🧠 MAIN
-# ==============================
-def main():
- token = TOKEN_PATH.read_text().strip()
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- conn = pymysql.connect(**DB_CONFIG)
- cur = conn.cursor()
-
- offset = 0
- total = None
-
- print("⏳ Starting patient sync...\n")
-
- while True:
- print(f"➡️ Fetching patients {offset}–{offset + PAGE_SIZE} ...")
-
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "filter": {},
- "pageInfo": {"first": PAGE_SIZE, "offset": offset},
- "sort": [{"field": "ReverseFullName", "sort": "ASC"}],
- }
-
- response = requests.post(
- GRAPHQL_URL,
- json={"query": QUERY, "variables": variables},
- headers=headers,
- timeout=30
- )
- response.raise_for_status()
- data = response.json()
-
- block = data["data"]["patientsList"]
- if total is None:
- total = block["count"]
- print(f"📌 Total patients: {total}\n")
-
- patients = block["patients"]
-
- if not patients:
- print("✅ No more patients. Finished.")
- break
-
- # save each patient
- for p in patients:
- save_patient_summary(cur, p)
-
- conn.commit()
-
- print(f" ✓ Saved {len(patients)} patients.")
-
- offset += PAGE_SIZE
- if offset >= total:
- print("\n✅ All patients downloaded.")
- break
-
- cur.close()
- conn.close()
-
-
-# ==============================
-if __name__ == "__main__":
- main()
diff --git a/Testy/07 Testy.py b/Testy/07 Testy.py
deleted file mode 100644
index a39e8c2..0000000
--- a/Testy/07 Testy.py
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from pathlib import Path
-
-TOKEN_PATH = Path("token.txt")
-GRAPHQL_URL = "https://api.medevio.cz/graphql"
-CLINIC_SLUG = "mudr-buzalkova"
-
-PATIENT_ID = "5a0a9ff0-bbe8-4fc7-a27d-b7b475ee2189"
-
-QUERY = """
-query ClinicPatientDetailModal_GetData(
- $clinicSlug: String!,
- $patientId: String!,
- $patientUuid: UUID!,
- $challengesStatus: ECRFChallengeStatus!,
- $locale: Locale!
-) {
- clinic: getClinic(clinicSlug: $clinicSlug) {
- id
- features
- sslSUKLCertificateId
- type
- ais
- slug
- ...ClinicWithTypeAndFeatures_Clinic
- ...PatientInfo_Clinic
- __typename
- }
- patient: getPatientForClinic(clinicSlug: $clinicSlug, patientId: $patientId) {
- ...ClinicPatientDetailModal_Patient
- __typename
- }
- challenges: listPatientChallenges2(
- clinicSlug: $clinicSlug
- patientId: $patientId
- status: $challengesStatus
- ) {
- ...ChallengeTableList_EcrfChallenge
- __typename
- }
- patientRequestsResponse: filterPatientRequestsForClinic(
- clinicSlug: $clinicSlug
- filter: {patientId: $patientUuid}
- pageInfo: {first: 1, offset: 0}
- ) {
- count
- items { id __typename }
- __typename
- }
- treatmentPlanPatients: listTreatmentPlanPatients(
- clinicSlug: $clinicSlug
- patientId: $patientUuid
- ) {
- ...ClinicPlanPatientList_PlanPatient
- __typename
- }
- premiumPlans: listClinicPremiumPlans(clinicSlug: $clinicSlug) {
- id
- __typename
- }
- mergeSuggestions: findMergeSuggestions(
- clinicSlug: $clinicSlug
- input: {existingPatientId: $patientUuid}
- ) {
- ...MergeSuggestionAlert_MergeSuggestionResult
- __typename
- }
- insuranceCards: getPatientDocuments(
- patientId: $patientUuid
- type: InsuranceCard
- ) {
- ...PatientInfo_InsuranceCard
- __typename
- }
-}
-
-fragment ClinicWithTypeAndFeatures_Clinic on Clinic {
- id
- type
- features
- __typename
-}
-
-fragment PatientInfo_Clinic on Clinic {
- country
- id
- slug
- ais
- ...ClinicWithTypeAndFeatures_Clinic
- __typename
-}
-
-fragment ClinicPatientDetailModal_Patient on ExtendedPatient {
- id
- isInClinic
- kind
- name
- isUnknownPatient
- sex
- surname
- identificationNumber
- editableByDoctor
- type
- key
- user { id name surname __typename }
- ...ClinicPatientDetail_Patient
- ...PatientInfo_AccountPatient
- ...ClinicPatientInfo_Patient
- __typename
-}
-
-fragment ClinicPatientDetail_Patient on ExtendedPatient {
- name
- surname
- email
- id
- identificationNumber
- isInClinic
- key
- phone
- sex
- type
- dob
- user { id __typename }
- isUnknownPatient
- hasMobileApp
- __typename
-}
-
-fragment PatientInfo_AccountPatient on ExtendedPatient {
- id
- createdAt
- key
- user {
- registrationCompletedTime
- deactivatedTime
- __typename
- }
- __typename
-}
-
-fragment ClinicPatientInfo_Patient on ExtendedPatient {
- anamnesisShared
- anamnesisStatusForClinic { updatedAt __typename }
- clinics { id name slug __typename }
- id
- isInClinic
- dob
- city
- familyMembers: family { __typename }
- houseNumber
- identificationNumber
- insuranceCompanyObject { id code name shortName __typename }
- kind
- name
- note
- owner { name surname __typename }
- key
- status
- street
- surname
- user { id email name phone surname __typename }
- userRelationship
- premiumPlanPatient { id __typename }
- sex
- tags(onlyImportant: false) { id name color icon __typename }
- type
- isUnknownPatient
- hasMobileApp
- __typename
-}
-
-fragment ChallengeTableList_EcrfChallenge on ECRFChallenge {
- id
- createdAt
- sentAt
- issuedToPatient {
- id
- identificationNumber
- name
- surname
- __typename
- }
- userECRF(locale: $locale) { id name __typename }
- patientRequestId
- status
- __typename
-}
-
-fragment MergeSuggestionAlert_MergeSuggestionResult on MergeSuggestionResult {
- extendedPatient { id __typename }
- matchResult
- __typename
-}
-
-fragment ClinicPlanPatientList_PlanPatient on TreatmentPlanPatient {
- id
- createdAt
- listPatient { id identificationNumber name key status surname __typename }
- treatmentPlan { id slug name __typename }
- __typename
-}
-
-fragment PatientInfo_InsuranceCard on PatientDocument {
- id
- contentType
- url
- downloadUrl
- __typename
-}
-"""
-
-
-def main():
- token = TOKEN_PATH.read_text().strip()
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "patientId": PATIENT_ID,
- "patientUuid": PATIENT_ID,
- "challengesStatus": "SENT",
- "locale": "cs",
- }
-
- print("⏳ Fetching patient detail…")
-
- r = requests.post(
- GRAPHQL_URL,
- json={"query": QUERY, "variables": variables},
- headers=headers,
- timeout=30
- )
-
- r.raise_for_status()
- data = r.json()
-
- print("\n📌 RAW DETAIL JSON:\n")
- print(json.dumps(data, indent=2, ensure_ascii=False))
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/08 Testy.py b/Testy/08 Testy.py
deleted file mode 100644
index 54c0ac8..0000000
--- a/Testy/08 Testy.py
+++ /dev/null
@@ -1,365 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-import pymysql
-from pathlib import Path
-
-# ==============================
-# CONFIG
-# ==============================
-TOKEN_PATH = Path("token.txt")
-GRAPHQL_URL = "https://api.medevio.cz/graphql"
-CLINIC_SLUG = "mudr-buzalkova"
-
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-PATIENT_ID = "5a0a9ff0-bbe8-4fc7-a27d-b7b475ee2189"
-
-
-# ==============================
-# HELPERS
-# ==============================
-def normalize_dt(dt_str):
- if not dt_str:
- return None
- dt_str = dt_str.replace("Z", "").replace("T", " ")
- if "." in dt_str:
- dt_str = dt_str.split(".")[0]
- return dt_str
-
-
-def save_patient_detail(cur, p):
- user = p.get("user") or {}
- ins = p.get("insuranceCompanyObject") or {}
- tags = p.get("tags") or []
- clinics = p.get("clinics") or []
-
- sql = """
- UPDATE medevio_pacienti SET
- email = %s,
- telefon = %s,
- dob = %s,
- street = %s,
- house_number = %s,
- city = %s,
-
- user_id = %s,
- user_email = %s,
- user_name = %s,
- user_surname = %s,
- user_phone = %s,
- user_reg_time = %s,
- user_deactivated_time = %s,
-
- created_at = %s,
- note = %s,
- has_mobile_app = %s,
- user_relationship = %s,
-
- pojistovna_code = %s,
- tags_json = %s,
- clinics_json = %s,
- last_update = NOW()
-
- WHERE id = %s
- """
-
- cur.execute(sql, (
- p.get("email"),
- p.get("phone"),
- p.get("dob"),
-
- p.get("street"),
- p.get("houseNumber"),
- p.get("city"),
-
- user.get("id"),
- user.get("email"),
- user.get("name"),
- user.get("surname"),
- user.get("phone"),
- normalize_dt(user.get("registrationCompletedTime")),
- normalize_dt(user.get("deactivatedTime")),
-
- normalize_dt(p.get("createdAt")),
- p.get("note"),
- 1 if p.get("hasMobileApp") else 0,
- p.get("userRelationship"),
-
- ins.get("code"),
- json.dumps(tags, ensure_ascii=False),
- json.dumps(clinics, ensure_ascii=False),
-
- p.get("id")
- ))
-
-
-# ==============================
-# FULL EXACT WORKING GRAPHQL QUERY
-# ==============================
-QUERY = """
-query ClinicPatientDetailModal_GetData(
- $clinicSlug: String!,
- $patientId: String!,
- $patientUuid: UUID!,
- $challengesStatus: ECRFChallengeStatus!,
- $locale: Locale!
-) {
- clinic: getClinic(clinicSlug: $clinicSlug) {
- id
- features
- sslSUKLCertificateId
- type
- ais
- slug
- ...ClinicWithTypeAndFeatures_Clinic
- ...PatientInfo_Clinic
- __typename
- }
- patient: getPatientForClinic(clinicSlug: $clinicSlug, patientId: $patientId) {
- ...ClinicPatientDetailModal_Patient
- __typename
- }
- challenges: listPatientChallenges2(
- clinicSlug: $clinicSlug
- patientId: $patientId
- status: $challengesStatus
- ) {
- ...ChallengeTableList_EcrfChallenge
- __typename
- }
- patientRequestsResponse: filterPatientRequestsForClinic(
- clinicSlug: $clinicSlug
- filter: {patientId: $patientUuid}
- pageInfo: {first: 1, offset: 0}
- ) {
- count
- items { id __typename }
- __typename
- }
- treatmentPlanPatients: listTreatmentPlanPatients(
- clinicSlug: $clinicSlug
- patientId: $patientUuid
- ) {
- ...ClinicPlanPatientList_PlanPatient
- __typename
- }
- premiumPlans: listClinicPremiumPlans(clinicSlug: $clinicSlug) {
- id
- __typename
- }
- mergeSuggestions: findMergeSuggestions(
- clinicSlug: $clinicSlug
- input: {existingPatientId: $patientUuid}
- ) {
- ...MergeSuggestionAlert_MergeSuggestionResult
- __typename
- }
- insuranceCards: getPatientDocuments(
- patientId: $patientUuid
- type: InsuranceCard
- ) {
- ...PatientInfo_InsuranceCard
- __typename
- }
-}
-
-fragment ClinicWithTypeAndFeatures_Clinic on Clinic {
- id
- type
- features
- __typename
-}
-
-fragment PatientInfo_Clinic on Clinic {
- country
- id
- slug
- ais
- ...ClinicWithTypeAndFeatures_Clinic
- __typename
-}
-
-fragment ClinicPatientDetailModal_Patient on ExtendedPatient {
- id
- isInClinic
- kind
- name
- isUnknownPatient
- sex
- surname
- identificationNumber
- editableByDoctor
- type
- key
- user { id name surname __typename }
- ...ClinicPatientDetail_Patient
- ...PatientInfo_AccountPatient
- ...ClinicPatientInfo_Patient
- __typename
-}
-
-fragment ClinicPatientDetail_Patient on ExtendedPatient {
- name
- surname
- email
- id
- identificationNumber
- isInClinic
- key
- phone
- sex
- type
- dob
- user { id __typename }
- isUnknownPatient
- hasMobileApp
- __typename
-}
-
-fragment PatientInfo_AccountPatient on ExtendedPatient {
- id
- createdAt
- key
- user {
- registrationCompletedTime
- deactivatedTime
- __typename
- }
- __typename
-}
-
-fragment ClinicPatientInfo_Patient on ExtendedPatient {
- anamnesisShared
- anamnesisStatusForClinic { updatedAt __typename }
- clinics { id name slug __typename }
- id
- isInClinic
- dob
- city
- familyMembers: family { __typename }
- houseNumber
- identificationNumber
- insuranceCompanyObject { id code name shortName __typename }
- kind
- name
- note
- owner { name surname __typename }
- key
- status
- street
- surname
- user { id email name phone surname __typename }
- userRelationship
- premiumPlanPatient { id __typename }
- sex
- tags(onlyImportant: false) { id name color icon __typename }
- type
- isUnknownPatient
- hasMobileApp
- __typename
-}
-
-fragment ChallengeTableList_EcrfChallenge on ECRFChallenge {
- id
- createdAt
- sentAt
- issuedToPatient {
- id
- identificationNumber
- name
- surname
- __typename
- }
- userECRF(locale: $locale) { id name __typename }
- patientRequestId
- status
- __typename
-}
-
-fragment MergeSuggestionAlert_MergeSuggestionResult on MergeSuggestionResult {
- extendedPatient { id __typename }
- matchResult
- __typename
-}
-
-fragment ClinicPlanPatientList_PlanPatient on TreatmentPlanPatient {
- id
- createdAt
- listPatient { id identificationNumber name key status surname __typename }
- treatmentPlan { id slug name __typename }
- __typename
-}
-
-fragment PatientInfo_InsuranceCard on PatientDocument {
- id
- contentType
- url
- downloadUrl
- __typename
-}
-"""
-
-
-# ==============================
-# MAIN
-# ==============================
-def main():
- token = TOKEN_PATH.read_text().strip()
-
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "patientId": PATIENT_ID,
- "patientUuid": PATIENT_ID,
- "challengesStatus": "SENT",
- "locale": "cs",
- }
-
- print(f"⏳ Fetching patient detail {PATIENT_ID}…")
-
- r = requests.post(
- GRAPHQL_URL,
- json={"query": QUERY, "variables": variables},
- headers=headers,
- timeout=30
- )
- r.raise_for_status()
- data = r.json()
-
- patient = data["data"]["patient"]
- if not patient:
- print("❌ Patient not found in API response!")
- return
-
- print("📥 Patient detail downloaded.")
-
- conn = pymysql.connect(**DB_CONFIG)
- cur = conn.cursor()
-
- save_patient_detail(cur, patient)
- conn.commit()
-
- print("✅ Patient detail saved to DB.")
-
- cur.close()
- conn.close()
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/09 Testy pt details all.py b/Testy/09 Testy pt details all.py
deleted file mode 100644
index 7933114..0000000
--- a/Testy/09 Testy pt details all.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import time
-import random
-import requests
-import pymysql
-from pathlib import Path
-
-from datetime import datetime
-
-# Patients with details_updated_at older than this date will be refreshed
-# UpdateOlderThan = datetime(2025, 2, 20) # example date
-UpdateOlderThan = None #když chceš všechny aktualizovat
-
-TOKEN_PATH = Path("token.txt")
-GRAPHQL_URL = "https://api.medevio.cz/graphql"
-CLINIC_SLUG = "mudr-buzalkova"
-
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-def normalize_dt(dt_str):
- if not dt_str:
- return None
- dt_str = dt_str.replace("Z", "").replace("T", " ")
- if "." in dt_str:
- dt_str = dt_str.split(".")[0]
- return dt_str
-
-def save_patient_detail(cur, p):
- user = p.get("user") or {}
- ins = p.get("insuranceCompanyObject") or {}
- tags = p.get("tags") or []
- clinics = p.get("clinics") or []
-
- sql = """
- UPDATE medevio_pacienti SET
- email = %s,
- telefon = %s,
- dob = %s,
- street = %s,
- house_number = %s,
- city = %s,
-
- user_id = %s,
- user_email = %s,
- user_name = %s,
- user_surname = %s,
- user_phone = %s,
- user_reg_time = %s,
- user_deactivated_time = %s,
-
- created_at = %s,
- note = %s,
- has_mobile_app = %s,
- user_relationship = %s,
-
- pojistovna_code = %s,
- tags_json = %s,
- clinics_json = %s,
- last_update = NOW(),
- details_updated_at = NOW()
-
- WHERE id = %s
- """
-
- cur.execute(sql, (
- p.get("email"),
- p.get("phone"),
- p.get("dob"),
-
- p.get("street"),
- p.get("houseNumber"),
- p.get("city"),
-
- user.get("id"),
- user.get("email"),
- user.get("name"),
- user.get("surname"),
- user.get("phone"),
- normalize_dt(user.get("registrationCompletedTime")),
- normalize_dt(user.get("deactivatedTime")),
-
- normalize_dt(p.get("createdAt")),
- p.get("note"),
- 1 if p.get("hasMobileApp") else 0,
- p.get("userRelationship"),
-
- ins.get("code"),
- json.dumps(tags, ensure_ascii=False),
- json.dumps(clinics, ensure_ascii=False),
-
- p.get("id")
- ))
-
-# === PLACEHOLDER: Insert your full GraphQL query here ===
-QUERY = Path("patient_detail.graphql").read_text(encoding="utf-8")
-
-def main():
- token = TOKEN_PATH.read_text().strip()
-
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- conn = pymysql.connect(**DB_CONFIG)
- cur = conn.cursor()
-
- if UpdateOlderThan:
- print(f"🔎 Updating patients with details_updated_at NULL or < {UpdateOlderThan}")
- cur.execute("""
- SELECT id, prijmeni, jmeno, details_updated_at
- FROM medevio_pacienti
- WHERE details_updated_at IS NULL OR details_updated_at < %s
- ORDER BY prijmeni, jmeno
- """, (UpdateOlderThan,))
- else:
- print("🔎 Updating only patients with details_updated_at NULL")
- cur.execute("""
- SELECT id, prijmeni, jmeno, details_updated_at
- FROM medevio_pacienti
- WHERE details_updated_at IS NULL
- ORDER BY prijmeni, jmeno
- """)
- patients = cur.fetchall()
-
- total = len(patients)
- print(f"⏳ Starting full patient detail sync for {total} patients...")
-
- for idx, row in enumerate(patients, start=1):
- pid = row["id"]
- name = f"{row.get('prijmeni','')}, {row.get('jmeno','')}"
- print(f"[{idx}/{total}] Updating: {name} ({pid})")
-
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "patientId": pid,
- "patientUuid": pid,
- "challengesStatus": "SENT",
- "locale": "cs",
- }
-
- try:
- r = requests.post(
- GRAPHQL_URL,
- json={"query": QUERY, "variables": variables},
- headers=headers,
- timeout=30
- )
- r.raise_for_status()
- js = r.json()
-
- p = js["data"]["patient"]
- if p:
- save_patient_detail(cur, p)
- conn.commit()
- print(" ✔ saved")
- else:
- print(" ⚠ no patient data returned")
-
- except Exception as e:
- print(f" ❌ ERROR: {e}")
- time.sleep(2)
- continue
-
- time.sleep(random.uniform(0.5, 1.5))
-
- conn.close()
- print("✅ DONE – full detail sync completed.")
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/10 Testy stahni pouze active pozadavky.py b/Testy/10 Testy stahni pouze active pozadavky.py
deleted file mode 100644
index 43c709a..0000000
--- a/Testy/10 Testy stahni pouze active pozadavky.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import pymysql
-import requests
-from pathlib import Path
-from datetime import datetime
-import time
-
-# ================================
-# 🔧 CONFIGURATION
-# ================================
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-BATCH_SIZE = 100
-
-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(path: Path) -> str:
- tok = path.read_text(encoding="utf-8").strip()
- if tok.startswith("Bearer "):
- tok = tok.split(" ", 1)[1]
- return tok
-
-
-# ================================
-# 🕒 DATETIME FORMAT
-# ================================
-def to_mysql_dt(iso_str):
- 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:
- return None
-
-
-# ================================
-# 💾 UPSERT
-# ================================
-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 ACTIVE PAGE
-# ================================
-def fetch_active(headers, offset):
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "queueId": None,
- "queueAssignment": "ANY",
- "pageInfo": {"first": BATCH_SIZE, "offset": offset},
- "locale": "cs",
- "state": "ACTIVE",
- }
-
- 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)
-
- print(f"\n=== Sync ACTIVE požadavků @ {datetime.now():%Y-%m-%d %H:%M:%S} ===")
-
- # -------------------------------
- # 🚀 FETCH ALL ACTIVE REQUESTS
- # -------------------------------
- offset = 0
- total_processed = 0
- total_count = None
-
- while True:
- batch, count = fetch_active(headers, offset)
-
- if total_count is None:
- total_count = count
- print(f"📡 Celkem ACTIVE v Medevio: {count}")
-
- if not batch:
- break
-
- for r in batch:
- upsert(conn, r)
-
- total_processed += len(batch)
- print(f" • {total_processed}/{total_count} ACTIVE processed")
-
- if offset + BATCH_SIZE >= count:
- break
-
- offset += BATCH_SIZE
- time.sleep(0.4)
-
- conn.close()
- print("\n✅ ACTIVE sync hotovo!\n")
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/11 Testy.py b/Testy/11 Testy.py
deleted file mode 100644
index b653a38..0000000
--- a/Testy/11 Testy.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from pathlib import Path
-
-TOKEN_PATH = Path("token.txt")
-GRAPHQL_URL = "https://api.medevio.cz/graphql"
-CLINIC_SLUG = "mudr-buzalkova"
-
-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)
- createdAt
- doneAt
- removedAt
- extendedPatient {
- name
- surname
- }
- }
-}
-"""
-
-def main():
- token = TOKEN_PATH.read_text().strip()
-
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "queueId": None,
- "queueAssignment": "ANY",
- "state": "ACTIVE",
- "pageInfo": {"first": 200, "offset": 100},
- "locale": "cs",
- }
-
- print("⏳ Testing ACTIVE request fetch (LEGACY API)…")
-
- r = requests.post(
- GRAPHQL_URL,
- json={"query": QUERY, "variables": variables},
- headers=headers,
- timeout=30
- )
- r.raise_for_status()
-
- js = r.json()
-
- # extract list
- requests_list = js.get("data", {}).get("requests", [])
-
- print("\n📌 Number of ACTIVE requests returned:", len(requests_list))
-
- print("\n📌 First 5 request IDs:")
- for item in requests_list[:5]:
- print(" •", item.get("id"))
-
- # debug dump if needed
- # print(json.dumps(js, indent=2, ensure_ascii=False))
-
- print("\n✅ Test completed.\n")
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/12 Testy.py b/Testy/12 Testy.py
deleted file mode 100644
index 9b94413..0000000
--- a/Testy/12 Testy.py
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import pymysql
-import requests
-from pathlib import Path
-from datetime import datetime
-
-# ================================
-# 🔧 CONFIGURATION
-# ================================
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-
-LIMIT = 300 # download the latest 300 requests
-
-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 "):
- return tok.split(" ", 1)[1]
- return tok
-
-# ================================
-# DATE PARSER
-# ================================
-def to_mysql_dt(iso_str):
- 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:
- return None
-
-# ================================
-# UPSERT
-# ================================
-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 LATEST 300 REQUESTS
-# ================================
-def fetch_latest_requests(headers):
- vars = {
- "clinicSlug": CLINIC_SLUG,
- "queueId": None,
- "queueAssignment": "ANY",
- "pageInfo": {"first": LIMIT, "offset": 0},
- "locale": "cs",
- "state": "DONE" # ALL STATES (ACTIVE, DONE, REMOVED)
- }
-
- payload = {
- "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2",
- "query": GRAPHQL_QUERY,
- "variables": vars,
- }
-
- 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", [])
-
-# ================================
-# 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)
-
- print(f"\n=== Downloading last {LIMIT} requests @ {datetime.now():%Y-%m-%d %H:%M:%S} ===")
-
- requests_list = fetch_latest_requests(headers)
-
- print(f"📌 Requests returned: {len(requests_list)}")
-
- for r in requests_list:
- upsert(conn, r)
-
- conn.close()
- print("\n✅ Done. Latest requests synced.\n")
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/13 testy report pacienti.py b/Testy/13 testy report pacienti.py
deleted file mode 100644
index ce99d91..0000000
--- a/Testy/13 testy report pacienti.py
+++ /dev/null
@@ -1,226 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import pymysql
-import openpyxl
-from openpyxl.styles import PatternFill, Font
-from openpyxl.utils import get_column_letter
-
-from datetime import datetime
-
-timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
-OUTPUT_PATH = fr"U:\Dropbox\!!!Days\Downloads Z230\{timestamp} medevio_patients_report.xlsx"
-
-# ============================
-# CONFIGURATION
-# ============================
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-# ============================
-# FUNCTIONS
-# ============================
-
-from openpyxl.styles import Border, Side
-
-thin_border = Border(
- left=Side(style='thin'),
- right=Side(style='thin'),
- top=Side(style='thin'),
- bottom=Side(style='thin')
-)
-
-def apply_thin_borders(ws):
- """Apply thin borders to all cells in the worksheet."""
- for row in ws.iter_rows():
- for cell in row:
- cell.border = thin_border
-
-def autofit_columns(ws):
- """Auto-adjust column widths based on longest cell content."""
- for col in ws.columns:
- max_length = 0
- col_letter = get_column_letter(col[0].column)
- for cell in col:
- try:
- if cell.value:
- max_length = max(max_length, len(str(cell.value)))
- except:
- pass
- ws.column_dimensions[col_letter].width = max_length + 2
-
-def apply_header_style(ws):
- """Make header BRIGHT YELLOW and bold."""
- fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")
- font = Font(bold=True)
-
- for cell in ws[1]:
- cell.fill = fill
- cell.font = font
-
-def create_compact_row(row):
- """Produce compact record with merged pojistovna, with user_relationship after prijmeni."""
-
- # insurance merged
- code = row.get("pojistovna_code") or ""
- naz = row.get("pojistovna_nazev") or ""
-
- if code and naz:
- poj = f"{code} ({naz})"
- elif code:
- poj = code
- elif naz:
- poj = naz
- else:
- poj = ""
-
- return {
- "id": row["id"],
- "jmeno": row["jmeno"],
- "prijmeni": row["prijmeni"],
-
- # 🔹 inserted here
- "user_relationship": row.get("user_relationship"),
-
- "rodne_cislo": row["rodne_cislo"],
- "dob": row["dob"],
- "telefon": row["telefon"],
- "email": row["email"],
- "pojistovna": poj,
- "status": row["status"],
- "has_mobile_app": row["has_mobile_app"],
- "registration_time": row["registration_time"],
- "last_update": row["last_update"],
- }
-
-def create_pozadavky_rows(rows):
- """Convert raw pozadavky SQL rows into rows for the Excel sheet."""
- output = []
- for r in rows:
- output.append({
- # 🔹 First the ID
- "id": r["id"],
-
- # 🔹 Your 3 patient columns immediately after ID
- "pacient_jmeno": r["pacient_jmeno"],
- "pacient_prijmeni": r["pacient_prijmeni"],
- "pacient_rodnecislo": r["pacient_rodnecislo"],
-
- # 🔹 Then all other fields in any order you prefer
- "displayTitle": r["displayTitle"],
- "createdAt": r["createdAt"],
- "updatedAt": r["updatedAt"],
- "doneAt": r["doneAt"],
- "removedAt": r["removedAt"],
- "attachmentsProcessed": r["attachmentsProcessed"],
- "messagesProcessed": r["messagesProcessed"],
- "communicationprocessed": r["communicationprocessed"],
- "questionnaireprocessed": r["questionnaireprocessed"],
- "lastSync": r["lastSync"],
- })
- return output
-
-
-# ============================
-# MAIN
-# ============================
-
-def main():
- print("📥 Connecting to MySQL...")
- conn = pymysql.connect(**DB_CONFIG)
-
- with conn:
- with conn.cursor() as cur:
- cur.execute("SELECT * FROM medevio_pacienti ORDER BY prijmeni, jmeno")
- patients = cur.fetchall()
-
- print(f"📊 Loaded {len(patients)} patients.")
-
- # Load pozadavky
-
- with conn.cursor() as cur:
- cur.execute("SELECT * FROM pozadavky ORDER BY createdAt DESC")
- pozadavky_rows = cur.fetchall()
-
- print(f"📄 Loaded {len(pozadavky_rows)} pozadavky.")
-
- wb = openpyxl.Workbook()
-
- # ---------------------------------
- # 1) FULL SHEET
- # ---------------------------------
- ws_full = wb.active
- ws_full.title = "Patients FULL"
-
- if patients:
- headers = list(patients[0].keys())
- ws_full.append(headers)
-
- for row in patients:
- ws_full.append([row.get(h) for h in headers])
-
- apply_header_style(ws_full)
- ws_full.freeze_panes = "A2"
- ws_full.auto_filter.ref = ws_full.dimensions
- autofit_columns(ws_full)
- apply_thin_borders(ws_full)
-
- # ---------------------------------
- # 2) COMPACT SHEET
- # ---------------------------------
- ws_compact = wb.create_sheet("Patients COMPACT")
-
- compact_rows = [create_compact_row(r) for r in patients]
- compact_headers = list(compact_rows[0].keys())
-
- ws_compact.append(compact_headers)
- for row in compact_rows:
- ws_compact.append([row.get(h) for h in compact_headers])
-
- apply_header_style(ws_compact)
- ws_compact.freeze_panes = "A2"
- ws_compact.auto_filter.ref = ws_compact.dimensions
- autofit_columns(ws_compact)
-
- # >>> ADD THIS <<<
- ur_col_index = compact_headers.index("user_relationship") + 1
- col_letter = get_column_letter(ur_col_index)
- ws_compact.column_dimensions[col_letter].width = 7.14
- apply_thin_borders(ws_compact)
-
- # ---------------------------------
- # 3) POZADAVKY SHEET
- # ---------------------------------
- ws_p = wb.create_sheet("Pozadavky")
-
- poz_list = create_pozadavky_rows(pozadavky_rows)
- headers_p = list(poz_list[0].keys()) if poz_list else []
-
- if headers_p:
- ws_p.append(headers_p)
- for row in poz_list:
- ws_p.append([row.get(h) for h in headers_p])
-
- apply_header_style(ws_p)
- ws_p.freeze_panes = "A2"
- ws_p.auto_filter.ref = ws_p.dimensions
- autofit_columns(ws_p)
- apply_thin_borders(ws_p)
-
-
- # ---------------------------------
- # SAVE
- # ---------------------------------
-
- wb.save(OUTPUT_PATH)
- print(f"✅ Excel report saved to:\n{OUTPUT_PATH}")
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/14 Testy updateat.py b/Testy/14 Testy updateat.py
deleted file mode 100644
index d215ca2..0000000
--- a/Testy/14 Testy updateat.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import requests
-from pathlib import Path
-import json
-
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-BATCH_SIZE = 100
-
-# přesně tvůj původní dotaz, beze změn
-# 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
-# }
-# }
-# }
-# }
-# """
-GRAPHQL_QUERY = r"""
-query ClinicRequestGrid_ListPatientRequestsForClinic2(
- $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)
-
- ### TIME FIELDS ADDED
- createdAt
- updatedAt
- doneAt
- removedAt
-
- extendedPatient {
- id
- identificationNumber
- name
- surname
- kind
- key
- type
- user {
- id
- name
- surname
- }
- owner {
- name
- surname
- }
- dob
- premiumPlanPatient {
- id
- premiumPlan {
- id
- }
- }
- status2
- tags(onlyImportant: true) {
- id
- }
- isUnknownPatient
- }
-
- invoice {
- id
- status
- amount
- currency
- dueAmount
- isOverdue
- refundedAmount
- settledAmount
- }
-
- lastMessage {
- createdAt
- id
- readAt
- sender {
- id
- name
- surname
- clinicId
- }
- text
- }
-
- priority
-
- queue {
- id
- name
- clinicPatientRequestQueueUsers {
- accountable {
- id
- name
- surname
- }
- id
- }
- }
-
- reservations {
- calendar {
- id
- internalName
- name
- }
- id
- canceledAt
- done
- start
- }
-
- tags(onlyImportant: true) {
- id
- }
-
- userECRF(locale: $locale) {
- id
- sid
- icon {
- color
- id
- urlSvg
- }
- ecrfSet {
- id
- name
- }
- }
-
- priceWhenCreated
- currencyWhenCreated
- createdByDoctor
- eventType
- clinicNotes {
- id
- }
- clinicMedicalRecord
- }
- }
-}
-"""
-
-def read_token(path: Path) -> str:
- tok = path.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": BATCH_SIZE, "offset": 0},
- "locale": "cs",
- "state": "ACTIVE",
- }
-
- payload = {
- "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2",
- "query": GRAPHQL_QUERY,
- "variables": variables,
- }
-
- print("\n===== ČISTÁ ODPOVĚĎ SERVERU =====\n")
-
- r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
-
- print(f"HTTP {r.status_code}\n")
- print(r.text) # <-- TISK NEUPRAVENÉHO JSONU
-
- print("\n===== KONEC ČISTÉ ODPOVĚDI =====\n")
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/15 test.py b/Testy/15 test.py
deleted file mode 100644
index d71905e..0000000
--- a/Testy/15 test.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import requests
-from pathlib import Path
-
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-BATCH_SIZE = 100
-TARGET_ID = "cbf6000d-a6ca-4059-88b7-dfdc27220762" # ← sem tvoje ID
-
-# ⭐ Updated GraphQL with lastMessage included
-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
- lastMessage {
- id
- createdAt
- updatedAt
- }
- extendedPatient {
- name
- surname
- identificationNumber
- }
- }
- }
-}
-"""
-
-def read_token(path: Path) -> str:
- tok = path.read_text(encoding="utf-8").strip()
- if tok.startswith("Bearer "):
- tok = tok.split(" ", 1)[1]
- return tok
-
-def fetch_active(headers, offset):
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "queueId": None,
- "queueAssignment": "ANY",
- "pageInfo": {"first": BATCH_SIZE, "offset": offset},
- "locale": "cs",
- "state": "ACTIVE",
- }
-
- payload = {
- "operationName": "ClinicRequestGrid_ListPatientRequestsForClinic2",
- "query": GRAPHQL_QUERY,
- "variables": variables,
- }
-
- r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
-
- if r.status_code != 200:
- print("HTTP status:", r.status_code)
- print(r.text)
- r.raise_for_status()
-
- data = r.json().get("data", {}).get("requestsResponse", {})
- return data.get("patientRequests", []), data.get("count", 0)
-
-
-def main():
- token = read_token(TOKEN_PATH)
- headers = {
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json"
- }
-
- print(f"=== Hledám updatedAt a lastMessage pro pozadavek {TARGET_ID} ===\n")
-
- offset = 0
- total_count = None
- found = False
-
- while True:
- batch, count = fetch_active(headers, offset)
-
- if total_count is None:
- total_count = count
-
- if not batch:
- break
-
- for r in batch:
- if r["id"] == TARGET_ID:
-
- print("Nalezeno!\n")
- print(f"id: {r['id']}")
- print(f"updatedAt: {r['updatedAt']}")
-
- lm = r.get("lastMessage") or {}
- print(f"lastMessage.createdAt: {lm.get('createdAt')}")
- print(f"lastMessage.updatedAt: {lm.get('updatedAt')}")
-
- found = True
- break
-
- if found:
- break
-
- if offset + BATCH_SIZE >= count:
- break
-
- offset += BATCH_SIZE
-
- if not found:
- print("❌ Požadavek nebyl nalezen mezi ACTIVE.")
-
- print("\n=== HOTOVO ===")
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/16 test.py b/Testy/16 test.py
deleted file mode 100644
index cbabdcf..0000000
--- a/Testy/16 test.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import pymysql
-import requests
-from pathlib import Path
-from datetime import datetime, timezone
-import time
-from dateutil import parser
-
-# ================================
-# 🔧 CONFIGURATION
-# ================================
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-BATCH_SIZE = 100
-
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-# ⭐ NOVÝ TESTOVANÝ DOTAZ – obsahuje lastMessage.createdAt
-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
- }
- }
- }
-}
-"""
-
-
-# ================================
-# 🧿 SAFE DATETIME PARSER (ALWAYS UTC → LOCAL)
-# ================================
-def to_mysql_dt_utc(iso_str):
- """
- Parse Medevio timestamps safely.
- Treat timestamps WITHOUT timezone as UTC.
- Convert to local time before saving to MySQL.
- """
- if not iso_str:
- return None
- try:
- dt = parser.isoparse(iso_str)
-
- # If tz is missing → assume UTC
- if dt.tzinfo is None:
- dt = dt.replace(tzinfo=timezone.utc)
-
- # Convert to local timezone
- dt_local = dt.astimezone()
-
- return dt_local.strftime("%Y-%m-%d %H:%M:%S")
- except:
- return None
-
-
-# ================================
-# 🔑 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
-
-
-# ================================
-# 💾 UPSERT (včetně správného updatedAt)
-# ================================
-def upsert(conn, r):
- p = r.get("extendedPatient") or {}
-
- # raw timestamps z API – nyní přes nový parser
- api_updated = to_mysql_dt_utc(r.get("updatedAt"))
-
- last_msg = r.get("lastMessage") or {}
- msg_updated = to_mysql_dt_utc(last_msg.get("createdAt"))
-
- # nejnovější změna
- def max_dt(a, b):
- if a and b:
- return max(a, b)
- return a or b
-
- final_updated = max_dt(api_updated, msg_updated)
-
- 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_utc(r.get("createdAt")),
- final_updated,
- to_mysql_dt_utc(r.get("doneAt")),
- to_mysql_dt_utc(r.get("removedAt")),
- p.get("name"),
- p.get("surname"),
- p.get("identificationNumber"),
- )
-
- with conn.cursor() as cur:
- cur.execute(sql, vals)
- conn.commit()
-
-
-# ================================
-# 📡 FETCH ACTIVE PAGE
-# ================================
-def fetch_active(headers, offset):
- variables = {
- "clinicSlug": CLINIC_SLUG,
- "queueId": None,
- "queueAssignment": "ANY",
- "pageInfo": {"first": BATCH_SIZE, "offset": offset},
- "locale": "cs",
- "state": "ACTIVE",
- }
-
- 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().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)
-
- print(f"\n=== Sync ACTIVE požadavků @ {datetime.now():%Y-%m-%d %H:%M:%S} ===")
-
- offset = 0
- total_processed = 0
- total_count = None
-
- while True:
- batch, count = fetch_active(headers, offset)
-
- if total_count is None:
- total_count = count
- print(f"📡 Celkem ACTIVE v Medevio: {count}")
-
- if not batch:
- break
-
- for r in batch:
- upsert(conn, r)
-
- total_processed += len(batch)
- print(f" • {total_processed}/{total_count} ACTIVE processed")
-
- if offset + BATCH_SIZE >= count:
- break
-
- offset += BATCH_SIZE
- time.sleep(0.4)
-
- conn.close()
- print("\n✅ ACTIVE sync hotovo!\n")
-
-
-# ================================
-if __name__ == "__main__":
- main()
diff --git a/Testy/18 Test.py b/Testy/18 Test.py
deleted file mode 100644
index f7d4590..0000000
--- a/Testy/18 Test.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import pymysql
-import requests
-from pathlib import Path
-from datetime import datetime
-from dateutil import parser
-
-# ================================
-# 🔧 CONFIGURATION
-# ================================
-TOKEN_PATH = Path("token.txt")
-CLINIC_SLUG = "mudr-buzalkova"
-LIMIT = 300 # stáhneme posledních 300 ukončených požadavků
-
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
- "cursorclass": pymysql.cursors.DictCursor,
-}
-
-# ⭐ Ověřený dotaz s lastMessage
-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 (UTC → MySQL)
-# ================================
-def to_mysql_dt(iso_str):
- if not iso_str:
- return None
- try:
- dt = parser.isoparse(iso_str) # ISO8601 → aware datetime (UTC)
- dt = dt.astimezone() # převede na lokální čas (CET/CEST)
- return dt.strftime("%Y-%m-%d %H:%M:%S")
- except:
- return None
-
-# ================================
-# UPSERT WITH MERGED UPDATED TIME
-# ================================
-def upsert(conn, r):
- p = r.get("extendedPatient") or {}
-
- # API pole
- api_updated = to_mysql_dt(r.get("updatedAt"))
-
- # poslední zpráva
- last_msg = r.get("lastMessage") or {}
- msg_at = to_mysql_dt(last_msg.get("createdAt"))
-
- # vybereme novější čas
- def max_dt(a, b):
- if a and b:
- return max(a, b)
- return a or b
-
- final_updated = max_dt(api_updated, msg_at)
-
- 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 LAST 300 DONE REQUESTS
-# ================================
-def fetch_done(headers):
- vars = {
- "clinicSlug": CLINIC_SLUG,
- "queueId": None,
- "queueAssignment": "ANY",
- "pageInfo": {"first": LIMIT, "offset": 0},
- "locale": "cs",
- "state": "DONE",
- }
-
- payload = {
- "operationName": "ClinicRequestList2",
- "query": GRAPHQL_QUERY,
- "variables": vars,
- }
-
- 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", [])
-
-# ================================
-# 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)
-
- print(f"\n=== Downloading last {LIMIT} DONE requests @ {datetime.now():%Y-%m-%d %H:%M:%S} ===")
-
- requests_list = fetch_done(headers)
- print(f"📌 Requests returned: {len(requests_list)}")
-
- for r in requests_list:
- upsert(conn, r)
-
- conn.close()
- print("\n✅ DONE - latest closed requests synced.\n")
-
-
-if __name__ == "__main__":
- main()
diff --git a/Testy/19 Test 2.py b/Testy/19 Test 2.py
deleted file mode 100644
index dba54c1..0000000
--- a/Testy/19 Test 2.py
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import os
-import shutil
-import pymysql
-import re
-from pathlib import Path
-from datetime import datetime
-
-# ==============================
-# ⚙️ CONFIGURATION
-# ==============================
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
-}
-
-BASE_DIR = Path(r"u:\Dropbox\Ordinace\Dokumentace_ke_zpracování\MP")
-BASE_DIR.mkdir(parents=True, exist_ok=True)
-
-
-def sanitize_name(name: str) -> str:
- return re.sub(r'[<>:"/\\|?*\x00-\x1F]', "_", name).strip()
-
-
-def clean_folder(folder: Path, valid_files: set):
- """Remove files that do NOT exist in MySQL for this request."""
- if not folder.exists():
- return
-
- for f in folder.iterdir():
- if f.is_file() and sanitize_name(f.name) not in valid_files:
- print(f"🗑️ Removing unexpected file: {f.name}")
- try:
- f.unlink()
- except Exception as e:
- print(f"⚠️ Cannot delete {f}: {e}")
-
-
-# ==============================
-# 📥 LOAD EVERYTHING IN ONE QUERY
-# ==============================
-conn = pymysql.connect(**DB_CONFIG)
-cur = conn.cursor(pymysql.cursors.DictCursor)
-
-print("📥 Loading ALL metadata + BLOBs with ONE MySQL query…")
-
-cur.execute("""
- SELECT
- d.id AS download_id,
- d.request_id,
- d.filename,
- d.file_content,
- p.updatedAt AS req_updated_at,
- p.pacient_jmeno AS jmeno,
- p.pacient_prijmeni AS prijmeni
- FROM medevio_downloads d
- JOIN pozadavky p ON d.request_id = p.id
- ORDER BY p.updatedAt DESC, d.created_at ASC
-""")
-
-rows = cur.fetchall()
-print(f"📦 Loaded {len(rows)} total file rows.\n")
-
-conn.close()
-
-# ==============================
-# 🔄 ORGANIZE ROWS PER REQUEST
-# ==============================
-requests = {} # req_id → list of file dicts
-
-for r in rows:
- req_id = r["request_id"]
- if req_id not in requests:
- requests[req_id] = []
- requests[req_id].append(r)
-
-print(f"📌 Unique requests: {len(requests)}\n")
-
-# ==============================
-# 🧠 MAIN LOOP – SAME LOGIC AS BEFORE
-# ==============================
-for req_id, filelist in requests.items():
-
- # ========== GET UPDATEDAT (same logic) ==========
- any_row = filelist[0]
- updated_at = any_row["req_updated_at"] or datetime.now()
- date_str = updated_at.strftime("%Y-%m-%d")
-
- prijmeni = sanitize_name(any_row["prijmeni"] or "Unknown")
- jmeno = sanitize_name(any_row["jmeno"] or "")
-
- folder_name = sanitize_name(f"{date_str} {prijmeni}, {jmeno} {req_id}")
- main_folder = BASE_DIR / folder_name
-
- # ========== VALID FILES ==========
- valid_files = {sanitize_name(r["filename"]) for r in filelist}
-
- # ========== FIND OLD FOLDERS ==========
- possible_dups = [
- f for f in BASE_DIR.iterdir()
- if f.is_dir() and req_id in f.name and f != main_folder
- ]
-
- # ========== MERGE OLD FOLDERS ==========
- for dup in possible_dups:
- print(f"♻️ Merging folder: {dup.name}")
-
- clean_folder(dup, valid_files)
- main_folder.mkdir(parents=True, exist_ok=True)
-
- for f in dup.iterdir():
- if f.is_file():
- target = main_folder / f.name
- if not target.exists():
- f.rename(target)
-
- shutil.rmtree(dup, ignore_errors=True)
-
- # ========== CLEAN MAIN FOLDER ==========
- main_folder.mkdir(parents=True, exist_ok=True)
- clean_folder(main_folder, valid_files)
-
- # ========== SAVE FILES (fast now) ==========
- for r in filelist:
- filename = sanitize_name(r["filename"])
- dest = main_folder / filename
-
- if dest.exists():
- continue
-
- content = r["file_content"]
- if not content:
- continue
-
- with open(dest, "wb") as f:
- f.write(content)
-
- print(f"💾 Saved: {dest.relative_to(BASE_DIR)}")
-
-print("\n🎯 Export complete.\n")
diff --git a/Testy/19 Test download at once.py b/Testy/19 Test download at once.py
deleted file mode 100644
index f586a42..0000000
--- a/Testy/19 Test download at once.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import pymysql
-from pathlib import Path
-import os
-import re
-
-# ==============================
-# ⚙️ CONFIGURATION
-# ==============================
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
-}
-
-OUTPUT = Path(r"d:\Dropbox\Ordinace\Dokumentace_ke_zpracování\mp1")
-OUTPUT.mkdir(exist_ok=True)
-
-
-def sanitize(name: str) -> str:
- return re.sub(r'[<>:"/\\|?*\x00-\x1F]', "_", name).strip()
-
-
-# ==============================
-# 📥 LOAD EVERYTHING IN ONE QUERY
-# ==============================
-def load_all_files():
- conn = pymysql.connect(**DB_CONFIG)
- cur = conn.cursor(pymysql.cursors.DictCursor)
-
- print("📥 Loading ALL medevio_downloads including BLOBs… (can take a few seconds)")
-
- cur.execute("""
- SELECT
- d.id AS download_id,
- d.request_id,
- d.attachment_id,
- d.filename,
- d.content_type,
- d.file_size,
- d.created_at,
- p.pacient_jmeno,
- p.pacient_prijmeni,
- d.file_content
- FROM medevio_downloads d
- JOIN pozadavky p ON d.request_id = p.id
- ORDER BY d.created_at
- """)
-
- rows = cur.fetchall()
- conn.close()
-
- print(f"📦 Loaded {len(rows)} BLOB records.")
- return rows
-
-
-# ==============================
-# 💾 SAVE ALL TO FILESYSTEM
-# ==============================
-def save_all(rows):
- saved = 0
-
- for r in rows:
- req_id = r["request_id"]
- jmeno = sanitize(r["pacient_jmeno"] or "")
- prijmeni = sanitize(r["pacient_prijmeni"] or "")
- filename = sanitize(r["filename"] or f"{r['download_id']}.bin")
-
- # Folder for each request
- folder = OUTPUT / f"{prijmeni}, {jmeno} {req_id}"
- folder.mkdir(exist_ok=True)
-
- dest = folder / filename
-
- # Skip existing
- if dest.exists():
- continue
-
- data = r["file_content"]
- if not data:
- continue
-
- with open(dest, "wb") as f:
- f.write(data)
-
- print(f"💾 Saved {dest}")
- saved += 1
-
- print(f"\n🎯 Done — {saved} files saved.")
-
-
-# ==============================
-# MAIN
-# ==============================
-if __name__ == "__main__":
- rows = load_all_files() # ONE query
- save_all(rows) # then write to disk
diff --git a/Testy/19 Test.py b/Testy/19 Test.py
deleted file mode 100644
index 2d4d5eb..0000000
--- a/Testy/19 Test.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import os
-import shutil
-import pymysql
-import re
-from pathlib import Path
-from datetime import datetime
-import time
-
-# ==============================
-# ⚙️ CONFIGURATION
-# ==============================
-DB_CONFIG = {
- "host": "192.168.1.76",
- "port": 3307,
- "user": "root",
- "password": "Vlado9674+",
- "database": "medevio",
- "charset": "utf8mb4",
-}
-
-BASE_DIR = Path(r"d:\Dropbox\Ordinace\Dokumentace_ke_zpracování\MP")
-BASE_DIR.mkdir(parents=True, exist_ok=True)
-
-
-def sanitize_name(name: str) -> str:
- """Replace invalid filename characters with underscore."""
- return re.sub(r'[<>:"/\\|?*\x00-\x1F]', "_", name).strip()
-
-
-# ==============================
-# 🧹 DELETE UNEXPECTED FILES
-# ==============================
-def clean_folder(folder: Path, valid_files: set):
- """Remove all files in folder that are NOT present in valid_files."""
- if not folder.exists():
- return
-
- for f in folder.iterdir():
- if f.is_file():
- if sanitize_name(f.name) not in valid_files:
- print(f"🗑️ Removing unexpected file: {f.name}")
- try:
- f.unlink()
- except Exception as e:
- print(f"⚠️ Could not delete {f}: {e}")
-
-
-# ==============================
-# 📦 DB CONNECTION
-# ==============================
-conn = pymysql.connect(**DB_CONFIG)
-
-cur_meta = conn.cursor(pymysql.cursors.DictCursor)
-cur_blob = conn.cursor()
-
-print("🔍 Loading metadata from DB (FAST)…")
-
-cur_meta.execute("""
- SELECT d.id AS download_id,
- d.request_id,
- d.filename,
- d.created_at,
- p.updatedAt AS req_updated_at,
- p.pacient_jmeno AS jmeno,
- p.pacient_prijmeni AS prijmeni
- FROM medevio_downloads d
- JOIN pozadavky p ON d.request_id = p.id
- ORDER BY p.updatedAt DESC
-""")
-
-rows = cur_meta.fetchall()
-print(f"📋 Found {len(rows)} attachment records.\n")
-
-# ==============================
-# 🧠 MAIN LOOP
-# ==============================
-processed_requests = set()
-
-for r in rows:
- req_id = r["request_id"]
-
- if req_id in processed_requests:
- continue
- processed_requests.add(req_id)
-
- # ========== FETCH ALL VALID FILES FOR THIS REQUEST ==========
- cur_meta.execute(
- "SELECT filename FROM medevio_downloads WHERE request_id=%s",
- (req_id,)
- )
- valid_files = {sanitize_name(row["filename"]) for row in cur_meta.fetchall()}
-
- # ========== FOLDER NAME BASED ON UPDATEDAT ==========
- updated_at = r["req_updated_at"] or datetime.now()
- date_str = updated_at.strftime("%Y-%m-%d")
-
- prijmeni = sanitize_name(r["prijmeni"] or "Unknown")
- jmeno = sanitize_name(r["jmeno"] or "")
-
- folder_name = f"{date_str} {prijmeni}, {jmeno} {req_id}"
- folder_name = sanitize_name(folder_name)
- main_folder = BASE_DIR / folder_name
-
- # ========== FIND OLD FOLDER (DUPLICATE) ==========
- # Any folder that contains "_" and is not main_folder is duplicate
- possible_dups = [
- f for f in BASE_DIR.iterdir()
- if f.is_dir() and req_id in f.name and f != main_folder
- ]
-
- # ========== MERGE DUPLICATES ==========
- for dup in possible_dups:
- print(f"♻️ Merging duplicate folder: {dup.name}")
-
- # 1) Clean unexpected files in dup
- clean_folder(dup, valid_files)
-
- # 2) Move files from dup to main folder
- main_folder.mkdir(parents=True, exist_ok=True)
-
- for f in dup.iterdir():
- if f.is_file():
- target = main_folder / f.name
- if not target.exists():
- f.rename(target)
-
- # 3) Remove the duplicate folder
- try:
- shutil.rmtree(dup, ignore_errors=True)
- except Exception as e:
- print(f"⚠️ Could not delete duplicate folder {dup}: {e}")
-
- # ========== CLEAN MAIN FOLDER ==========
- clean_folder(main_folder, valid_files)
-
- # ========== DOWNLOAD MISSING FILES ==========
- main_folder.mkdir(parents=True, exist_ok=True)
-
- for filename in valid_files:
- dest = main_folder / filename
- if dest.exists():
- continue
-
- # fetch blob only now
- start = time.perf_counter()
- cur_blob.execute(
- "SELECT file_content FROM medevio_downloads "
- "WHERE request_id=%s AND filename=%s",
- (req_id, filename)
- )
- row = cur_blob.fetchone()
- if not row:
- continue
- end = time.perf_counter()
- print(f"⏱ Took {end - start:.4f} seconds")
-
- content = row[0]
- if not content:
- continue
-
- with open(dest, "wb") as f:
- f.write(content)
-
- print(f"💾 Wrote: {dest.relative_to(BASE_DIR)}")
-
-print("\n🎯 Export complete.\n")
-
-cur_blob.close()
-cur_meta.close()
-conn.close()